www.mtkn.jp

Manuscripts for my personal webpage.
git clone https://git.mtkn.jp/www.mtkn.jp
Log | Files | Refs | README

commit 3c77026715f13e35d4424bb05e70b986380b0a1a
parent 0e163c0fe8cd7314f3bca9bbb21ff80215347dcc
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Tue,  9 May 2023 07:35:52 +0900

fix html errors

Diffstat:
Mdata/weblog | 2++
Mman/computer/rp2040_1.html | 17++++++++++-------
Mpub/about.html | 8++++----
Mpub/books/978-4-06-288451-8.html | 8++++----
Mpub/books/index.html | 8++++----
Mpub/computer/archlinux_installation.html | 8++++----
Mpub/computer/index.html | 8++++----
Mpub/computer/rp2040_1.html | 26++++++++++++++------------
Mpub/computer/rtx1200-qos.html | 8++++----
Mpub/computer/setting_up_web_server.html | 8++++----
Mpub/computer/what-i-use.html | 8++++----
Mpub/computer/xlib_playground1.html | 8++++----
Mpub/computer/xlib_playground2.html | 8++++----
Mpub/computer/xlib_playground3.html | 8++++----
Mpub/computer/xlib_playground4.html | 8++++----
Mpub/computer/xlib_playground5.html | 8++++----
Mpub/computer/xlib_playground6.html | 8++++----
Mpub/draft/how_to_throw_away_smart_phone.html | 8++++----
Mpub/draft/keitai.html | 8++++----
Mpub/draft/light.html | 8++++----
Mpub/draft/medical_care.html | 8++++----
Mpub/draft/migration.html | 8++++----
Mpub/draft/myrica_rubra.html | 8++++----
Mpub/draft/openbsd_installation.html | 8++++----
Mpub/draft/opinion.html | 8++++----
Mpub/draft/safety_convenience.html | 8++++----
Mpub/draft/setting_up_mail_server.html | 8++++----
Mpub/draft/xlib2.html | 8++++----
Mpub/error/404.html | 8++++----
Mpub/error/moved.html | 8++++----
Mpub/farm/index.html | 8++++----
Mpub/farm/journal/2021.html | 8++++----
Mpub/farm/journal/2022.html | 8++++----
Mpub/index.html | 8++++----
Mpub/journal/index.html | 8++++----
Mpub/journal/posts/20200719.html | 8++++----
Mpub/journal/posts/20200723.html | 8++++----
Mpub/journal/posts/20200725.html | 8++++----
Mpub/journal/posts/20200727.html | 8++++----
Mpub/journal/posts/20200801.html | 8++++----
Mpub/journal/posts/20200802.html | 8++++----
Mpub/journal/posts/20200804.html | 8++++----
Mpub/journal/posts/20200808.html | 8++++----
Mpub/journal/posts/20200917.html | 8++++----
Mpub/journal/posts/20200918.html | 8++++----
Mpub/journal/posts/20200919.html | 8++++----
Mpub/journal/posts/20200925.html | 8++++----
Mpub/journal/posts/20200926.html | 8++++----
Mpub/journal/posts/20201003.html | 8++++----
Mpub/journal/posts/20201201.html | 8++++----
Mpub/journal/posts/20201202.html | 8++++----
Mpub/journal/posts/20201209.html | 8++++----
Mpub/journal/posts/20201210.html | 8++++----
Mpub/journal/posts/20210106.html | 8++++----
Mpub/journal/posts/20210806.html | 8++++----
Mpub/journal/posts/20211129.html | 8++++----
Mpub/journal/posts/20211214.html | 8++++----
Mpub/journal/posts/20220513.html | 8++++----
Mpub/journal/posts/20220729.html | 8++++----
Mpub/journal/posts/20220730.html | 8++++----
Mpub/journal/posts/20220813.html | 8++++----
Mpub/journal/posts/20220814.html | 8++++----
Mpub/journal/posts/20221023.html | 8++++----
Mpub/journal/posts/20221031.html | 8++++----
Mpub/journal/posts/20221228.html | 8++++----
Mpub/journal/posts/20230119.html | 8++++----
Mpub/kitchen/index.html | 8++++----
Mpub/kitchen/r4_osechi.html | 8++++----
Mpub/kitchen/recipe/tonkotsu_ramen.html | 8++++----
Mpub/poetry/index.html | 8++++----
Mpub/rss.xml | 3064++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mpub/sitemap.xml | 2+-
Mtemp/header.html | 8++++----
73 files changed, 1832 insertions(+), 1823 deletions(-)

diff --git a/data/weblog b/data/weblog @@ -194,3 +194,5 @@ 1682953200 /computer/what-i-use.html 1682953200 /computer/what-i-use.html 1682953200 /index.html +1683558000 /computer/rp2040_1.html +1683558000 /computer/rp2040_1.html diff --git a/man/computer/rp2040_1.html b/man/computer/rp2040_1.html @@ -78,11 +78,13 @@ code ----------> object ------> elf --------> bin -------> with --------> crc <h2>CRC(巡回冗長検査)</h2> <p> 入力のデータをごにょごにょしてある値を出力する。\ +</p> <blockquote cite="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB"> <p> データ転送等に伴う偶発的な誤りの検査によく使われている<sup>[5]</sup>。 </p> </blockquote> +<p> らしい。 </p> <p> @@ -289,7 +291,7 @@ over MSC (Mass Storage Class; aka removable flash drive)<sup>[6]</sup>. <p> このファイルに変換する上で必要な情報はGitHubのmicrosoft/uf2<sup>[6]</sup>に\ 表として纏められている: -<blockquote cite"https://github.com/microsoft/uf2"> +<blockquote cite="https://github.com/microsoft/uf2"> <table> <thead><tr> <th>Offset</th><th>Size</th><th>Value</th> @@ -534,7 +536,7 @@ setup_xip: ldr r3, rom_base ldrh r0, [r3, #0x14] // rom_func_table - ldr r1, =('C' | 'X' << 8) // _flash_enter_cmd_xip() + ldr r1, =('C' | 'X' &lt;&lt; 8) // _flash_enter_cmd_xip() ldrh r2, [r3, #0x18] // rom_table_lookup blx r2 blx r0 @@ -548,7 +550,8 @@ XIPの設定が完了すれば、次はメインのプログラムを実行す エントリーポイントの指定、スタックポインタの初期値の設定、ベクターテーブル\ の設定である。Armのマニュアル<sup>[7]</sup>によると、\ 初期スタックポインタとエントリーポイントはベクターテーブルの\ -<code>0x0</code>バイト目と<code>0x4</code>バイト目に書くことになっている: +<code>0x0</code>バイト目と<code>0x4</code>バイト目に書くことになっている:\ +</p> <blockquote cite="https://developer.arm.com/documentation/ddi0419/c/System-Level-Architecture/System-Level-Programmers--Model/ARMv6-M-exception-model/Exception-number-definition"> <table> <caption> @@ -564,7 +567,7 @@ Table 7.4. Vector table format </caption><colgroup><col><col></colgroup><thead><tr><th>Word offset in table</th><th>Description, for all pointer address values</th></tr></thead><tbody><tr><td>0</td><td>SP_main. This is the reset value of the Main stack pointer.</td></tr><tr><td>Exception Number</td><td>Exception using that Exception Number</td></tr></tbody> </table> </blockquote> - +<p> また、ベクターテーブルはメインのプログラムの先頭に置くことにする。\ メインのプログラムはFlash Second Stageが占有する256バイトの直後、\ フラッシュROMの257バイト目から配置することにする。\ @@ -591,7 +594,7 @@ m0plus_vtor: なお以上のコードは<code>.boot2</code>という名前のセクションにしてある。 </p> -<h2>メインのコード(<code>main.s</code>)<h2> +<h2>メインのコード(<code>main.s</code>)</h2> <h3>ベクターテーブル</h3> <p> メインのコードの最初には上で説明したベクターテーブルを配置する。\ @@ -729,7 +732,7 @@ GPIO25番の機能を選択するにはIO_BANK0_BASE(<code>0x40014000</code>)か io_bank0_base: .word 0x40014000 -</pre></code> +</code></pre> <h3>GPIOの出力を有効化</h3> <p> @@ -783,7 +786,7 @@ SIO: GPIO_OUT_XORレジスタがそれである。\ <pre><code>\ // blink led on gpio25 ldr r4, sio_base - mov r5, r0 // r0 = 1 << 25 + mov r5, r0 // r0 = 1 &lt;&lt; 25 loop: str r5, [r4, #0x1c] // SIO: GPIO_OUT_XOR bl delay diff --git a/pub/about.html b/pub/about.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>自己紹介</title> </head> <body> diff --git a/pub/books/978-4-06-288451-8.html b/pub/books/978-4-06-288451-8.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>不死身の特攻兵</title> </head> <body> diff --git a/pub/books/index.html b/pub/books/index.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>本棚</title> </head> <body> diff --git a/pub/computer/archlinux_installation.html b/pub/computer/archlinux_installation.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Arch Linuxのインストール</title> </head> <body> diff --git a/pub/computer/index.html b/pub/computer/index.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>電算機</title> </head> <body> diff --git a/pub/computer/rp2040_1.html b/pub/computer/rp2040_1.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>RP2040 SDKなしでLチカ</title> </head> <body> @@ -67,11 +67,13 @@ code ----------> object ------> elf --------> bin -------> with --------> crc <h2>CRC(巡回冗長検査)</h2> <p> -入力のデータをごにょごにょしてある値を出力する。<blockquote cite="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB"> +入力のデータをごにょごにょしてある値を出力する。</p> +<blockquote cite="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB"> <p> データ転送等に伴う偶発的な誤りの検査によく使われている<sup>[5]</sup>。 </p> </blockquote> +<p> らしい。 </p> <p> @@ -247,7 +249,7 @@ over MSC (Mass Storage Class; aka removable flash drive)<sup>[6]</sup>. </blockquote> <p> このファイルに変換する上で必要な情報はGitHubのmicrosoft/uf2<sup>[6]</sup>に表として纏められている: -<blockquote cite"https://github.com/microsoft/uf2"> +<blockquote cite="https://github.com/microsoft/uf2"> <table> <thead><tr> <th>Offset</th><th>Size</th><th>Value</th> @@ -443,7 +445,7 @@ RP2040の内蔵ROMの<code>0x00000018</code>番地に関数を検索するため ldr r3, rom_base ldrh r0, [r3, #0x14] // rom_func_table - ldr r1, =('C' | 'X' << 8) // _flash_enter_cmd_xip() + ldr r1, =('C' | 'X' &lt;&lt; 8) // _flash_enter_cmd_xip() ldrh r2, [r3, #0x18] // rom_table_lookup blx r2 blx r0 @@ -453,7 +455,7 @@ rom_base: </code></pre> <p> -XIPの設定が完了すれば、次はメインのプログラムを実行するための準備である。エントリーポイントの指定、スタックポインタの初期値の設定、ベクターテーブルの設定である。Armのマニュアル<sup>[7]</sup>によると、初期スタックポインタとエントリーポイントはベクターテーブルの<code>0x0</code>バイト目と<code>0x4</code>バイト目に書くことになっている: +XIPの設定が完了すれば、次はメインのプログラムを実行するための準備である。エントリーポイントの指定、スタックポインタの初期値の設定、ベクターテーブルの設定である。Armのマニュアル<sup>[7]</sup>によると、初期スタックポインタとエントリーポイントはベクターテーブルの<code>0x0</code>バイト目と<code>0x4</code>バイト目に書くことになっている:</p> <blockquote cite="https://developer.arm.com/documentation/ddi0419/c/System-Level-Architecture/System-Level-Programmers--Model/ARMv6-M-exception-model/Exception-number-definition"> <table> <caption> @@ -469,7 +471,7 @@ Table 7.4. Vector table format </caption><colgroup><col><col></colgroup><thead><tr><th>Word offset in table</th><th>Description, for all pointer address values</th></tr></thead><tbody><tr><td>0</td><td>SP_main. This is the reset value of the Main stack pointer.</td></tr><tr><td>Exception Number</td><td>Exception using that Exception Number</td></tr></tbody> </table> </blockquote> - +<p> また、ベクターテーブルはメインのプログラムの先頭に置くことにする。メインのプログラムはFlash Second Stageが占有する256バイトの直後、フラッシュROMの257バイト目から配置することにする。RP2040のベクターテーブルはM0PLUS: VTOR(<code>0xe0000000 + 0xed08</code>)というレジスタに書き込むことで設定する。以上をまとめると以下のコードになる:</p> <pre><code> ldr r0, flash_main ldr r1, m0plus_vtor @@ -489,7 +491,7 @@ m0plus_vtor: <p>なお以上のコードは<code>.boot2</code>という名前のセクションにしてある。 </p> -<h2>メインのコード(<code>main.s</code>)<h2> +<h2>メインのコード(<code>main.s</code>)</h2> <h3>ベクターテーブル</h3> <p> メインのコードの最初には上で説明したベクターテーブルを配置する。ここでは割り込みの処理は考えないので、初期スタックポインタとエントリーポイントだけである。初期スタックポインタはSRAMの最後?(<code>0x20040000</code>)、エントリーポイントはエントリーポイントのラベルを用いて設定した。</p> @@ -561,7 +563,7 @@ GPIO25番の機能を選択するにはIO_BANK0_BASE(<code>0x40014000</code>)か io_bank0_base: .word 0x40014000 -</pre></code> +</code></pre> <h3>GPIOの出力を有効化</h3> <p> @@ -595,7 +597,7 @@ although some individual registers (e.g. GPIO) have set/clear/xor aliases. <pre><code> // blink led on gpio25 ldr r4, sio_base - mov r5, r0 // r0 = 1 << 25 + mov r5, r0 // r0 = 1 &lt;&lt; 25 loop: str r5, [r4, #0x1c] // SIO: GPIO_OUT_XOR bl delay diff --git a/pub/computer/rtx1200-qos.html b/pub/computer/rtx1200-qos.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>ルーター(RTX1200)のQoS機能を利用して帯域を制限した</title> </head> <body> diff --git a/pub/computer/setting_up_web_server.html b/pub/computer/setting_up_web_server.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Webサーバーの設定</title> </head> <body> diff --git a/pub/computer/what-i-use.html b/pub/computer/what-i-use.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>使用しているハードウェア、ソフトウェア</title> </head> <body> diff --git a/pub/computer/xlib_playground1.html b/pub/computer/xlib_playground1.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Xlibで遊んでみる1</title> </head> <body> diff --git a/pub/computer/xlib_playground2.html b/pub/computer/xlib_playground2.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Xlibで遊んでみる2</title> </head> <body> diff --git a/pub/computer/xlib_playground3.html b/pub/computer/xlib_playground3.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Xlibで遊んでみる3</title> </head> <body> diff --git a/pub/computer/xlib_playground4.html b/pub/computer/xlib_playground4.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Xlibで遊んでみる4</title> </head> <body> diff --git a/pub/computer/xlib_playground5.html b/pub/computer/xlib_playground5.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Xlibで遊んでみる5</title> </head> <body> diff --git a/pub/computer/xlib_playground6.html b/pub/computer/xlib_playground6.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Xlibで遊んでみる6</title> </head> <body> diff --git a/pub/draft/how_to_throw_away_smart_phone.html b/pub/draft/how_to_throw_away_smart_phone.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>携帯電話捨てた</title> </head> <body> diff --git a/pub/draft/keitai.html b/pub/draft/keitai.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>携帯電話を持たない生活</title> </head> <body> diff --git a/pub/draft/light.html b/pub/draft/light.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>照明は(あんまり)いらない</title> </head> <body> diff --git a/pub/draft/medical_care.html b/pub/draft/medical_care.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>医療</title> </head> <body> diff --git a/pub/draft/migration.html b/pub/draft/migration.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>移住計画</title> </head> <body> diff --git a/pub/draft/myrica_rubra.html b/pub/draft/myrica_rubra.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>ヤマモモ</title> </head> <body> diff --git a/pub/draft/openbsd_installation.html b/pub/draft/openbsd_installation.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>OpenBSDインストール</title> </head> <body> diff --git a/pub/draft/opinion.html b/pub/draft/opinion.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>意見の言い方</title> </head> <body> diff --git a/pub/draft/safety_convenience.html b/pub/draft/safety_convenience.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>安全装置と便利なもの</title> </head> <body> diff --git a/pub/draft/setting_up_mail_server.html b/pub/draft/setting_up_mail_server.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>OpenBSD、OpenSMTPDとDovecotによるメールサーバー構築</title> </head> <body> diff --git a/pub/draft/xlib2.html b/pub/draft/xlib2.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Xlibで遊んでみる</title> </head> <body> diff --git a/pub/error/404.html b/pub/error/404.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>404 Not Found</title> </head> <body> diff --git a/pub/error/moved.html b/pub/error/moved.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>移転しました</title> </head> <body> diff --git a/pub/farm/index.html b/pub/farm/index.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>農業</title> </head> <body> diff --git a/pub/farm/journal/2021.html b/pub/farm/journal/2021.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>令和3年 農業日誌</title> </head> <body> diff --git a/pub/farm/journal/2022.html b/pub/farm/journal/2022.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>令和4年 農業日誌</title> </head> <body> diff --git a/pub/index.html b/pub/index.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>松露庵</title> </head> <body> diff --git a/pub/journal/index.html b/pub/journal/index.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>日記</title> </head> <body> diff --git a/pub/journal/posts/20200719.html b/pub/journal/posts/20200719.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>最初の投稿</title> </head> <body> diff --git a/pub/journal/posts/20200723.html b/pub/journal/posts/20200723.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>多少体裁を整えました</title> </head> <body> diff --git a/pub/journal/posts/20200725.html b/pub/journal/posts/20200725.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Django使うのやめようかな</title> </head> <body> diff --git a/pub/journal/posts/20200727.html b/pub/journal/posts/20200727.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>けの日</title> </head> <body> diff --git a/pub/journal/posts/20200801.html b/pub/journal/posts/20200801.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Djangoやめました</title> </head> <body> diff --git a/pub/journal/posts/20200802.html b/pub/journal/posts/20200802.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>今日の一汁一菜</title> </head> <body> diff --git a/pub/journal/posts/20200804.html b/pub/journal/posts/20200804.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>localからの投稿テスト</title> </head> <body> diff --git a/pub/journal/posts/20200808.html b/pub/journal/posts/20200808.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>冷蔵庫と豊かな生活</title> </head> <body> diff --git a/pub/journal/posts/20200917.html b/pub/journal/posts/20200917.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>pythonやめました</title> </head> <body> diff --git a/pub/journal/posts/20200918.html b/pub/journal/posts/20200918.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>仕事</title> </head> <body> diff --git a/pub/journal/posts/20200919.html b/pub/journal/posts/20200919.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>工場見学</title> </head> <body> diff --git a/pub/journal/posts/20200925.html b/pub/journal/posts/20200925.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>rsyncによる投稿テスト</title> </head> <body> diff --git a/pub/journal/posts/20200926.html b/pub/journal/posts/20200926.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>SSLに対応しました。</title> </head> <body> diff --git a/pub/journal/posts/20201003.html b/pub/journal/posts/20201003.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>何をして生きようか</title> </head> <body> diff --git a/pub/journal/posts/20201201.html b/pub/journal/posts/20201201.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>畑をさせてもらえることになった。</title> </head> <body> diff --git a/pub/journal/posts/20201202.html b/pub/journal/posts/20201202.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>たまねぎを植えた。</title> </head> <body> diff --git a/pub/journal/posts/20201209.html b/pub/journal/posts/20201209.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>畝を繋げた</title> </head> <body> diff --git a/pub/journal/posts/20201210.html b/pub/journal/posts/20201210.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>小松菜の種を蒔いた。</title> </head> <body> diff --git a/pub/journal/posts/20210106.html b/pub/journal/posts/20210106.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>x220から投稿テスト</title> </head> <body> diff --git a/pub/journal/posts/20210806.html b/pub/journal/posts/20210806.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>畑を返すことになった。</title> </head> <body> diff --git a/pub/journal/posts/20211129.html b/pub/journal/posts/20211129.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>赤目自然農塾</title> </head> <body> diff --git a/pub/journal/posts/20211214.html b/pub/journal/posts/20211214.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>無題</title> </head> <body> diff --git a/pub/journal/posts/20220513.html b/pub/journal/posts/20220513.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>坊主になるために薬の服用を強要されそうになってる。</title> </head> <body> diff --git a/pub/journal/posts/20220729.html b/pub/journal/posts/20220729.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>RSS作った</title> </head> <body> diff --git a/pub/journal/posts/20220730.html b/pub/journal/posts/20220730.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>新型コロナウイルスとその対策に関する個人的見解</title> </head> <body> diff --git a/pub/journal/posts/20220813.html b/pub/journal/posts/20220813.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>正座が出来ていた頃に戻るには</title> </head> <body> diff --git a/pub/journal/posts/20220814.html b/pub/journal/posts/20220814.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>田舎の夏休み</title> </head> <body> diff --git a/pub/journal/posts/20221023.html b/pub/journal/posts/20221023.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>寺に適応できない</title> </head> <body> diff --git a/pub/journal/posts/20221031.html b/pub/journal/posts/20221031.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>大阪駅にて</title> </head> <body> diff --git a/pub/journal/posts/20221228.html b/pub/journal/posts/20221228.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>Holy Shit!</title> </head> <body> diff --git a/pub/journal/posts/20230119.html b/pub/journal/posts/20230119.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>寺を辞めた</title> </head> <body> diff --git a/pub/kitchen/index.html b/pub/kitchen/index.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>台所</title> </head> <body> diff --git a/pub/kitchen/r4_osechi.html b/pub/kitchen/r4_osechi.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>令和4年正月のおせち料理</title> </head> <body> diff --git a/pub/kitchen/recipe/tonkotsu_ramen.html b/pub/kitchen/recipe/tonkotsu_ramen.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>豚骨ラーメン</title> </head> <body> diff --git a/pub/poetry/index.html b/pub/poetry/index.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title>詩</title> </head> <body> diff --git a/pub/rss.xml b/pub/rss.xml @@ -5,1806 +5,1808 @@ <description>ウェブページの更新履歴</description> <language>ja-jp</language> <link>https://www.mtkn.jp</link> -<lastBuildDate>Tue, 2 May 2023 14:36:37 +0900</lastBuildDate> -<pubDate>Tue, 2 May 2023 14:36:37 +0900</pubDate> +<lastBuildDate>Tue, 9 May 2023 07:35:21 +0900</lastBuildDate> +<pubDate>Tue, 9 May 2023 07:35:21 +0900</pubDate> <docs>https://www.rssboard.org/rss-specification</docs> <item> -<title>使用しているハードウェア、ソフトウェア</title> -<link>https://www.mtkn.jp/computer/what-i-use.html</link> -<guid>https://www.mtkn.jp/computer/what-i-use.html</guid> -<pubDate>Tue, 2 May 2023 00:00:00 +0900</pubDate> -<description><![CDATA[<h1>使用しているハードウェア、ソフトウェア</h1> -<time>2023-05-02</time>更新<br> -<time>2021-12-13</time>作成 -<h2>ノートパソコン</h2> -<p>メインのパソコン。</p> -<dl> -<dt>ハードウェア: Macbook Air 2013</dt> -<dd>ThinkPad辞めた。ファンがあまりにもうるさい。ThinkPadの前に使ってたMacbook Airを引っ張り出してバッテリー交換して使ってみたらファンがめっちゃ静か。多分ほぼ回ってない。M1 Macbook Airが欲しくなってきた。</dd> -<dt>OS: Arch Linux</dt> -<dd>本当はOpenBSDがいいんやけどMacbook AirだとWi-Fiも使えやんしいろいろサポートが悪いので...</dd> - -<dt>Window Manager: <a href="https://git.mtkn.jp/dwm">dwm</a></dt> - -<dt>Terminal: <a href="https://git.mtkn.jp/st">st</a></dt> - -<dt>Text Editor: nvi</dt> -<dd>vimは辞めた。OpenBSDにあったnviが丁度いい。日本語を使うのでUTF8に対応したnvi2を使っている。Arch Linuxだとちょっと使い勝手が違う。コマンド履歴が編集できないのが不便である。Samとかacmeとか使ってみたいけど日本語入力できやんのはちょっと...</dd> +<title>RP2040 SDKなしでLチカ</title> +<link>https://www.mtkn.jp/computer/rp2040_1.html</link> +<guid>https://www.mtkn.jp/computer/rp2040_1.html</guid> +<pubDate>Tue, 9 May 2023 00:00:00 +0900</pubDate> +<description><![CDATA[<h1>RP2040 SDKなしでLチカ</h1> +<time>2023-04-25</time> -<dt>Browser: firefox</dt> -<dd>もうちょっとましなのないんかな。UIころころ変わるし、重いし、嫌い。JavaScriptがないと困るので仕方なく使っているが...</dd> +<h2>はじめに</h2> +<p> +パタヘネのRISC-V<sup>[1]</sup>版を買って一通り読んだらアセンブリ言語で組込のプログラミングがしたくなった。RISC-Vのマイコンボードが欲しかったのだが、安くていい感じのものが見付からなかった。代わりに秋月電子通商でArmのものがあった。RP2040マイコンボードキット<sup>[2]</sup>というものである。ウェブ上の情報も多く、データシート<sup>[3]</sup>もしっかりしていそうなので、とりあえずこれを買ってみた。</p> +<p> +一般的にはSDK<sup>[4]</sup>をダウンロードしてあらかじめ用意されたライブラリを使って開発するようだが、これはビルドシステムとしてcmakeというのを使っている。これがOpenBSDでは何かエラーがでて動かなかった。僕はこういう便利ツールが嫌いだ。どうせ使わんからいいんやけど。関係ないけど途中から開発環境がLinuxに替わった。SDKには便利な関数がたくさん用意されているので楽である。ハードウェアの面倒な部分がプログラマから見えないようにしているからである。しかし今回はその面倒な部分に触れてみたくて買ったので、SDKを使うと意味がない。</p> +<p> +ということでSDKなしで開発してみる。とりあえず定番のLチカをば。</p> +<p> +ソースコード: <a href="https://git.mtkn.jp/rp2040">git</a> +</p> -<dt>Mail Cdtent: neomutt</dt> -</dl> +<h2>動作環境</h2> +<ul> +<li>Arch Linux 6.2.12-arch1-1 + <ul> + <li>arm-none-eabi-binutils 2.40-1</li> + <li>GNU Make 4.4.1</li> + </ul> +</li> +<li>OpenBSD 7.3 + <ul> + <li>arm-none-eabi-binutils 2.31.1</li> + <li>make (バージョン?)</li> + </ul> +※<code>make flash</code>は動かん。<code>dmesg</code>でデバイス確認して手動でマウントする必要がある。 +</li> +</ul> -<h2>デスクトップ</h2> -<p>学生のときに組んだ。無駄にハイスペック。この上RTX2060も積んでたが、OpenBSDで使えないので解雇した。あんまり使ってない。</p> -<dl> -<dt>マザーボード: ASRock Z390 Pro4</dt> -<dt>CPU: Intel Core i7-9700K</dt> -<dt>メモリ: センチュリーマイクロ 8GB * 2</dt> -<dd>国産</dd> -<dt>ストレージ: KimMiDi SSD 256GB</dt> -<dd>ThinkPad買ったときについてきたやつ。</dd> -<dt>モニタ: Eizo FlexScan EV2451</dt> -<dd>綺麗やけど質量が大きい。</dd> -<dt>OS: OpenBSD</dt> -<dd>いい</dd> -<dt>ソフト: ノートパソコンと同じ</dt> -</dl> +<h2>Boot Process</h2> +<p> +RP2040は電源を入れるといくつかの段階(ここでは関係ないので省略。データシート「2.8.1 Processor Controlled Boot Sequence」に詳しく書いてある)を踏んだあと、外部のフラッシュROMの先頭から256バイトを内部のSRAMにコピーして、フラッシュにプログラムが書き込まれているかどうか確認する。RP2040はフラッシュの先頭252バイトから計算したCRC32チェックサムを、直後の253バイト目から256バイトに記録することになっている。起動時にこのチェックサムを確認することで、フラッシュにプログラムが書き込まれているかどうか確かめている。コピーした最後の4バイトと起動時に最初の252バイトから計算したチェックサムが一致していれば、そのままコピーしてきた256バイトの先頭にPCをセットして実行を開始する。一致しなければUSBデバイスモードに切り替わり、パソコンに接続するとストレージとして認識される。このストレージにUF2という形式に変換したプログラムをコピーするとプログラムがフラッシュROMやSRAMに書き込まれる。 +</p> +<p> +以上のことから、プログラムを実行するためにはCRC32を計算し、UF2という形式に変換することが必要である。ソースコードからの流れは以下の通り: +</p> +<pre>source bin bin with +code ----------> object ------> elf --------> bin -------> with --------> crc32 in + crc32 uf2 format + assemble link objcopy bincrc bin2uf2 +</pre> -<h2>家のサーバー</h2> +<h2>CRC(巡回冗長検査)</h2> <p> -バックアップ用 +入力のデータをごにょごにょしてある値を出力する。</p> +<blockquote cite="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB"> +<p> +データ転送等に伴う偶発的な誤りの検査によく使われている<sup>[5]</sup>。 </p> -<dl> -<dt>ハードウェア: Dell D520</dt> -<dd>おじいちゃんの家にころがってたのをもらってきた。</dd> -<dt>OS: OpenBSD</dt> -</dl> +</blockquote> +<p> +らしい。 +</p> +<p> +入力のビットを一列に並べて、除数で「割り算」していく。この「割り算」が多項式の除算に似ているので、この除数をCRC多項式というらしい。ただし多項式の除算と違い、引き算するところをXORする。CRC32の場合、除数は33ビットである。33ビットで割ると32ビットの余りが残る。この余りがCRC32のチェックサムである。除数は色々あるようだが、標準的なものがWikipedia<sup>[5]</sup>に列挙されている。除数<code>1011</code>を使ったCRC3の計算の手順は以下の通り: +</p> +<pre><code>1110101011011100110101101101111 入力(適当) +1011 除数(4ビット) +------------------------------- + 101101011011100110101101101111 結果(入力と除数のXOR) + 1011 + ------------------------------ + 00001011011100110101101101111 + 1011 + ------------------------- + 000011100110101101101111 + 1011 + -------------------- + 1010110101101101111 + 1011 + ------------------- + 001110101101101111 + 1011 + ---------------- + 101101101101111 + 1011 + --------------- + 00001101101111 + 1011 + ---------- + 110101111 + 1011 + --------- + 11001111 + 1011 + -------- + 1111111 + 1011 + ------- + 100111 + 1011 + ------ + 01011 + 1011 + ---- + 000 CRC3チェックサム +</code></pre> +<p> +普通の割り算と基本は同じであるが、引き算の部分だけXORになっている。</p> +<p> +以上の計算をプログラムの先頭252バイトに対して、33ビットの除数を用いて行う。データの並べ方は、上の例において左側を先頭に、フラッシュROM上の0番地から、各バイトは最上位ビットから順に並べる。入力のデータは253バイト目から256バイト目に<code>0</code>をひっつけて計算する。これは多分予め長さが分からないデータでも計算できるようにしたかったからかな。除数は<code>0x104c11db7</code>である(最上位ビットは常に1なのでデータシートでは省略されている)。</p> +<p> +入力データは1バイトづつ処理したいみたいである。多分通信等で使う都合である。この時XORは結合則が成り立つので1バイト処理した結果と次のバイトとをXORして次の処理の入力として利用することができる: +</p> +<pre><code>111000111000000110000110111000111000001010010011111000111000000110010011 入力(適当) +|......| +111000110000000000000000000000000 先頭1バイト +100000100110000010001110110110111 除数 +------------------------------------------------------------------------ +011000010110000010001110110110111 + 100000100110000010001110110110111 + ----------------------------------------------------------------------- + 010000001010000110010011011011001 + 100000100110000010001110110110111 + ---------------------------------------------------------------------- + 000000110010001110101000000000101 +|......| + 110010001110101000000000101000000 1バイト目の結果 + |......| + 10000001 入力の2バイト目 + ---------------------------------------------------------------- + 010010011110101000000000101000000 1バイト目の結果と2バイト目のXOR + 100000100110000010001110110110111 除数 + ---------------------------------------------------------------- + 000100011011010010001111100110111 + . + . + . +</code></pre> +<p> +以上の操作は以下のようなアルゴリズムのループで実装できる。</p> +<ul> +<li>前回の結果と、入力データの次のバイトをXOR</li> +<li> + <ul> + <li>先頭の1ビットが1の場合、除数とXORを取り左シフト</li> + <li>先頭の1ビットが0の場合、そのまま左シフト</li> + </ul> +</li> +</ul> +<p> +これを<code>for</code>ループで回す都合上、最初のバイトもXORを取る。上の例では最初は<code>0x0</code>とXORを取っているが、この値を<code>0x0</code>以外にすることもできる。そうした方がいろいろいいこともあるらしい。RP2040では<code>0xffffffff</code>を使う。更にこの工程を32ビットの<code>int</code>だけで行うことを考える: +</p> +<pre><code>111000111000000110000110111000111000001010010011111000111000000110010011 入力(適当) -<h2>ウェブサーバー</h2> -<p>このウェブページ用</p> -<dl> -<dt>VPS: さくらのVPS</dt> -<dd>ちょっと高い(7078円/12ヶ月)。OpenBSDを入れられる。</dd> -<dt>OS: OpenBSD</dt> -<dt>httpサーバー: Openbsd httpd</dt> -<dd>manが分かりやすい。</dd> -<dt>smtpサーバー: OpenSMTPD</dt> -<dd>manが分かりやすい。</dd> -<dt>imapサーバー: dovecot</dt> -<dd>manはあんまり分かり易くない。<dd> -</dl> +11111111111111111111111111111111 0xffffffff +11100011000000000000000000000000 先頭1バイトを24ビットシフト +-------------------------------- XOR +00011100111111111111111111111111 +先頭1ビットが0なので1ビットシフト +-------------------------------- シフト +00111001111111111111111111111110 +先頭1ビットが0なので1ビットシフト +-------------------------------- シフト +01110011111111111111111111111100 +先頭1ビットが0なので1ビットシフト +-------------------------------- シフト +11100111111111111111111111111000 +先頭1ビットが1なので1ビットシフトした後、除数の下位32ビットとXOR: +11001111111111111111111111110000 シフト +00000100110000010001110110110111 除数の下位32ビット +-------------------------------- XOR +11001011001111101110001001000111 +先頭1ビットが1なので1ビットシフトした後、除数の下位32ビットとXOR: +10010110011111011100010010001110 シフト +00000100110000010001110110110111 除数の下位32ビット +-------------------------------- XOR +10010010101111001101100100111001 +先頭1ビットが1なので1ビットシフトした後、除数の下位32ビットとXOR: +00100101011110011011001001110010 シフト +00000100110000010001110110110111 除数の下位32ビット +-------------------------------- XOR +00100001101110001010111111000101 +先頭1ビットが0なので1ビットシフト +-------------------------------- シフト +01000011011100010101111110001010 +先頭1ビットが0なので1ビットシフト +-------------------------------- シフト +10000110111000101011111100010100 1バイト目の結果 -<h2>理想</h2> -<dl> -<dt>CPU: RISC-V</dt> -<dd>はやく家庭用コンピュータの世界に来てほしい</dd> -<dt>ファン: レス</dt> -<dd>静音性は優先度がかなり高い。</dd> -<dt>メモリ: 8GB</dt> -<dd>そんないらん</dd> -<dt>モニター: 60fpsでるカラーの電子ペーパー</dt> -<dt>キーボード: PFU製</dt> -<dd>macbook airに戻っても特にストレスないからキーストロークはそんなにいらんかな</dd> -<dt>バッテリー: 24時間くらい</dt> -<dt>OS: Plan9かOpenBSD</dt> -<dd>ハードウェアは全部ドキュメント公開してくれ</dd> -</dl> -]]></description> -</item> -<item> -<title>Xlibで遊んでみる6</title> -<link>https://www.mtkn.jp/computer/xlib_playground6.html</link> -<guid>https://www.mtkn.jp/computer/xlib_playground6.html</guid> -<pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> -<description><![CDATA[<h1>Xlibで遊んでみる6</h1> -<time>2023-01-25</time> +10000001 入力の2バイト目 +-------------------------------- XOR +00000111111000101011111100010100 +先頭1ビットが0なので1ビットシフト +-------------------------------- シフト +00001111110001010111111000101000 +. +. +. +</code></pre> +<p> +これを実装したのが以下のコード:</p> +<pre><code>uint32_t +crc32(uint8_t *idata, size_t len) +{ + uint32_t pol = 0x04C11DB7; + uint32_t c = 0xFFFFFFFF; + uint32_t b; + for (int i = 0; i &lt; len; i++) { + b = idata[i] &lt;&lt; 24; + c ^= b; + for (int j = 0; j &lt; 8; j++) { + c = c &gt;&gt; 31 & 1 ? c &lt;&lt; 1 ^ pol : c &lt;&lt; 1; + } + } + + return c; +} +</code></pre> <p> -前回: <a href="xlib_playground5.html">Xlibで遊んでみる5</a> +<code>main()</code>関数では上の<code>crc32()</code>に、<code>idata</code>として入力となるバイナリデータの先頭を、<code>len</code>として<code>252</code>を渡してCRC32を計算させる。その後、出力先のファイルに入力元のデータをコピーしていき、253バイト目から256バイト目だけ、計算したCRC32に置き換える。入力元のこの場所にデータが書き込まれていないかどうかは確かめていない。 </p> + +<h2>UF2(USB Flashing Format)</h2> <p> -言語: C言語<br /> -ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> +Microsoftが開発したフラッシュ書き込み用のファイル形式らしい: +<blockquote cite="https://github.com/microsoft/uf2"> +<p> +UF2 is a file format, developed by Microsoft for PXT (also known as +Microsoft MakeCode), that is particularly suitable for flashing microcontrollers +over MSC (Mass Storage Class; aka removable flash drive)<sup>[6]</sup>. </p> +</blockquote> +<p> +このファイルに変換する上で必要な情報はGitHubのmicrosoft/uf2<sup>[6]</sup>に表として纏められている: +<blockquote cite="https://github.com/microsoft/uf2"> +<table> +<thead><tr> +<th>Offset</th><th>Size</th><th>Value</th> +</tr></thead> +<tbody> +<tr> +<td>0</td> +<td>4</td> +<td>First magic number, <code>0x0A324655</code> (<code>"UF2\n"</code>)</td> +</tr> +<tr> +<td>4</td> +<td>4</td> +<td>Second magic number, <code>0x9E5D5157</code></td> +</tr> +<tr> +<td>8</td> +<td>4</td> +<td>Flags</td> +</tr> +<tr> +<td>12</td> +<td>4</td> +<td>Address in flash where the data should be written</td> +</tr> +<tr> +<td>16</td> +<td>4</td> +<td>Number of bytes used in data (often 256)</td> +</tr> +<tr> +<td>20</td> +<td>4</td> +<td>Sequential block number; starts at 0</td> +</tr> +<tr> +<td>24</td> +<td>4</td> +<td>Total number of blocks in file</td> +</tr> +<tr> +<td>28</td> +<td>4</td> +<td>File size or board family ID or zero</td> +</tr> +<tr> +<td>32</td> +<td>476</td> +<td>Data, padded with zeros</td> +</tr> +<tr> +<td>508</td> +<td>4</td> +<td>Final magic number, <code>0x0AB16F30</code></td> +</tr> +</tbody> +</table> +</blockquote> -<h2>ワールドマップの作成</h2> <p> -ゲームのワールドマップを作製した。ここでは文字列として登録した。なにもないところは「<code>.</code>」、ブロックの場所は「<code>b</code>」、プレーヤーは「<code>p</code>」とした: +RP2040のデータシート<sup>[3]</sup>「2.8.4.2 UF2 Format Details」を見ると、8バイト目のFlagsは、28バイト目にファミリーIDが書き込まれていることを示す<code>0x00002000</code>、12バイト目は、書き込みを行うフラッシュROMの先頭アドレスである<code>0x10000000</code>に、各ブロックの先頭からの位置を足したもの、16バイト目の、各ブロックのデータサイズは256バイト、28バイト目のファミリーIDは<code>0xe48bff56</code>である。あとは表の通り3つのマジックナンバーをセットし、32バイト目以降にデータを書き込み、20バイト目と24バイト目にブロックの通し番号と総数をそれぞれ書き込めばいい。ブロックの通し番号はデータのついでに書き込めるが、総数はデータを全部さばいた後でないと分からないので、最後全てのブロックにまとめて書き込むようにした。できたのが以下のコード: </p> -<pre><code>char worldmap[WORLD_WIDTH * WORLD_HEIGHT + 1] = -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"........b......................................................................." -"................................................................................" -"................................................................................" -"....b..........................................................................." -"................................................................................" -"................b..............................................................." -"..........................................................b..........b.........." -"................................................................................" -".......................b........................................................" -"...........................................b...................................." -"...........................................b...................................." -"................................................................................" -"..................b............................................................." -"................................................................................" -"...........................................b...................................." -"................................................................................" -"................................................................................" -"...........................b...................................................." -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"....................................bbbbbbbbbb.................................." -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"..............................................bbbbbbbbbb........................" -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"....................................bbbbbbbbbb.................................." -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"..........................bbbbbbbbbb............................................" -"................................................................................" -"................................................................................" -"................................................................................" -"................................................................................" -"................bbbbbbbbbb......................................................" -"................................................................................" -"................................................................................" -"...p............................................................................" -"bbbbbbbbbbbbbbbbbbbbbbbbb.......bbbbbbbbbbbbbbbbbbbbbbbb...bbbbbbbbbbbbbbbbbbbbb" -"........................b.......b......................b...b...................." -"........................b.......b......................b...b...................." -"........................b.......b......................b...b...................." -"........................b.......b......................b...b...................."; -</code></pre> - -<h2>プレイヤーの作成</h2> -<p>プレイヤーには重力をかけたいので、まずは四角形に加速度を追加:</p> -<pre><code>struct rect { - float ppx, ppy; - float px, py; - float vx, vy; - float ax, ay; // acceleration - int w, h; - int m; -}; -</code></pre> -<p>ワールドマップを読み込み、その際にプレイヤーに重力を付加:</p> -<pre><code>struct rect block[NUM_RECT]; -struct rect player; +<pre><code>#include &lt;stdio.h&gt; +#include &lt;stdint.h&gt; +#include &lt;stdlib.h&gt; +#include &lt;string.h&gt; -/* ... */ - int bi = 0; - for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) { - if (world_map[i] == 'b') { - block[bi].ppx = block[bi].px = i % WORLD_WIDTH * BLOCK_SIZE; - block[bi].ppy = block[bi].py = i / WORLD_WIDTH * BLOCK_SIZE; - block[bi].ax = 0; - block[bi].ay = 0; - block[bi].vx = 0; - block[bi].vy = 0; - block[bi].w = block[bi].h = BLOCK_SIZE; - block[bi].m = block[bi].w * block[bi].h; - bi++; - } else if (world_map[i] == 'p') { - player.ppx = player.px = i % WORLD_WIDTH * BLOCK_SIZE; - player.ppy = player.py = i / WORLD_WIDTH * BLOCK_SIZE; - player.vx = 0; - player.vy = 0; - player.ax = 0; - player.ay = GRAVITY; - player.w = player.h = BLOCK_SIZE; - player.m = player.w * player.h; +size_t +fwrite32l(uint32_t d, FILE *f) +{ + int i; + uint8_t b; + for (i = 0; i &lt; 32; i += 8) { + b = (uint8_t) (d &gt;&gt; i & 0xff); + fwrite(&amp;b, 1, 1, f); + if (ferror(f)) { + fprintf(stderr, "Fwrite32l: write error.\n"); + return 0; } } -</code></pre> + return 4; +} + +int +main(int argc, char *argv[]) +{ + FILE *src = NULL, *dst = NULL; + size_t sdata = 476; + int retnum = 0; + + uint32_t mag1 = 0x0A324655; + uint32_t mag2 = 0x9E5D5157; + uint32_t flags = 0x00002000; // familyID present + uint32_t addr = 0x10000000; + uint32_t nbyte = 256; + uint32_t blk = 0; + uint32_t nblk = 0; + uint32_t famid = 0xe48bff56; + uint8_t data[sdata]; + uint32_t mag3 = 0x0AB16F30; + + memset(data, 0, sdata); + + if (argc != 3) { + fprintf(stderr, "Usage: %s src dst\n", argv[0]); + exit(1); + } -<p>ユーザーからの入力を受けとり、プレイーヤの加速度等を変更。<code>A</code>、<code>D</code>でそれぞれ左右に加速し、地面に接しているときに<code>space</code>キーでジャンプさせる: -</p> -<pre><code>void -handle_inputs(int key_state[]) -{ - if (key_state[KEY_Q] == KEY_DOWN){ - next_menu = GAME_OVER; - return; + if ((src = fopen(argv[1], "rb")) == NULL) { + fprintf(stderr, "Could not open %s.\n", argv[1]); + retnum = 1; + goto defer; } - if (key_state[KEY_D] == KEY_DOWN) { - if (player.vx > 0) { - player.ax = 500; - } else { - player.ax = 1000; - } - } else if (key_state[KEY_A] == KEY_DOWN) { - if (player.vx > 0) { - player.ax = -1000; - } else { - player.ax = -500; - } - } else { - if (player_is_falling) - player.ax = -player.vx; - else - player.ax = -3 * player.vx; + if ((dst = fopen(argv[2], "wb")) == NULL) { + fprintf(stderr, "Could not open %s.\n", argv[2]); + retnum = 1; + goto defer; } + + while (!feof(src)) { + fwrite32l(mag1, dst); + fwrite32l(mag2, dst); + fwrite32l(flags, dst); + fwrite32l(addr, dst); + fwrite32l(nbyte, dst); + fwrite32l(blk, dst); + fwrite32l(nblk, dst); // dummy + fwrite32l(famid, dst); - if (player.vx < -200) player.vx = -200; - if (player.vx > 200) player.vx = 200; - if (!player_is_falling && key_state[KEY_SPACE] == KEY_DOWN) - player.vy = -450; -} -</code></pre> + fread(data, 1, nbyte, src); + if (ferror(src)) { + fprintf(stderr, "Read error: %s.\n", argv[1]); + retnum = 1; + goto defer; + } + fwrite(data, 1, sdata, dst); + if (ferror(src)) { + fprintf(stderr, "Write error: %s.\n", argv[2]); + retnum = 1; + goto defer; + } -<p>変更した加速度は<code>rect_next_tick()</code>関数で次の位置を計算するのに使用。また画面の下に落ちた時にゲームオーバーになるように設定:</p> -<pre><code>void -rect_next_tick(struct rect *s, long ndt) // nano second -{ - s->ppx = s->px; - s->ppy = s->py; - s->vx += s->ax * ndt / 1000 / 1000 / 1000; - s->vy += s->ay * ndt / 1000 / 1000 / 1000; - s->px += s->vx * ndt / 1000 / 1000 / 1000; - s->py += s->vy * ndt / 1000 / 1000 / 1000; + fwrite32l(mag3, dst); - // bind within the window - if (s->px < 0) { - s->px = 0; - //s->vx *= -1; + addr += nbyte; + blk++; + nblk++; } - if (win_width < s->px + s->w) { - s->px = win_width - s->w; - //s->vx *= -1; + + for (int i = 0; i &lt; nblk; i++) { + if (i == 0) + if (fseek(dst, 24, SEEK_SET) &lt; 0) { + fprintf(stderr, "Seek error: %s.\n argv[2]"); + retnum = 1; + goto defer; + } + fwrite32l(nblk, dst); + if (i &lt; nblk - 1) + if(fseek(dst, 512 - 4, SEEK_CUR) &lt; 0){ + fprintf(stderr, "Seek error: %s.\n argv[2]"); + retnum = 1; + goto defer; + } } - // game over when fall out of the screen - if (s->py > win_height) - next_menu = GAME_OVER; + +defer: + if (src) + fclose(src); + if (dst) + fclose(dst); + return retnum; } </code></pre> - - -<h2>完成品</h2> -<p> -<a href="https://git.mtkn.jp/xlib_playground/file/ex6/ex6.c.html">git</a> -</p> +<p><code>fwrite32l()</code>関数は指定されたファイルに32ビットの整数を下位バイトから順に書き込む関数である。バイトオーダーとかややこしそうなので作っておいたけど必要なのかな?あと名前が気に入らない。</p> <p> -<video controls> -<source src="videos/ex6.webm" type="video/webm"> -</video> +CRC32のチェックサムが書き込まれたバイナリファイルを、このプログラムでUF2に変換し、生成されたファイルをUSBストレージとして接続したRP2040にコピーすればフラッシュROMに書き込まれる。 </p> -<h2>参考</h2> -<ul> -<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> -</ul> -]]></description> -</item> -<item> -<title>Xlibで遊んでみる5</title> -<link>https://www.mtkn.jp/computer/xlib_playground5.html</link> -<guid>https://www.mtkn.jp/computer/xlib_playground5.html</guid> -<pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> -<description><![CDATA[<h1>Xlibで遊んでみる5</h1> -<time>2023-01-03</time> - +<h2>Flash Second Stage</h2> <p> -前回: <a href="xlib_playground4.html">Xlibで遊んでみる4</a> +RP2040に電源を投入し、CRC32のチェックが通った後、フラッシュROMからコピーされたプログラムの先頭から実行が開始される。このコピーされた部分で、その後の動作に必要な各種の設定を行うことになる。RP2040のデータシートには、フラッシュROMとSSIコントローラのXIPを設定するようにと書かれている。XIPはExecute in Placeの略で、フラッシュROMの内容をCPUから直接実行するものである。SSIはSynchronous Serial Interfaceの略で、周辺機器と情報のやりとりをする通信方式である。RP2040はチップに内蔵されたこのSSIコントローラを通して、外部のフラッシュROMと通信しているのだが、このコントローラを適切に設定すればフラッシュROMの内容がCPUから直接アクセスできる<code>0x10000000</code>番地以降にマップされる。これによりフラッシュROMから内部のSRAMにデータをコピーすることなく命令を実行できるので、速くて便利だという。 </p> <p> -言語: C言語<br /> -ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> +しかしこのSSIコントローラはSynopsysという会社のDW_apb_ssiというIPを使っているようで、データシートのSSIコントローラの章は多分Synopsysの人が書いている。その他の章はRaspberry Pi財団の書いたブリティッシュイングリッシュだが、この部分だけ多分ネイティブじゃない人の書いたいい加減な英語である。誤植も多い。何日かかけて理解しようとしたがよく分からん。不毛なので一旦諦めた。</p> +<p> +RP2040には内部にもROMがあり、はバージョン情報や電源を投入した時の動作、その他便利な関数が書き込まれている。この関数の中に外部のフラッシュROMとSSIコントローラを設定するものも含まれているので、今回はこれを利用した。ただしこの方法だとフラッシュROMとの通信方式がStandard SPIのままなので少し遅いらしい。詳しくはデータシートの「2.3.8. Bootrom Contents」を参照。 </p> - -<h2>円の衝突判定とその処理</h2> <p> -前回四角形で行っていた衝突判定とその処理を今回は円でした。衝突の判定は二つの円の中心間の距離と、各円の半径の和を比較するだけなので簡単である: +RP2040の内蔵ROMの<code>0x00000018</code>番地に関数を検索するための関数がある。この関数に<code>0x00000014</code>番地の<code>rom_func_table</code>と、各関数に割り当てられた二文字の文字列を渡せば、欲しい関数へのポインタが返ってくる。なお、二文字の文字列はそれぞれASCIIコードで現し、二文字目を8ビットシフトしたものと1文字目のORを取ったものを渡すことになっている。今回欲しい関数はフラッシュROMをXIPに設定するもの(<code>_flash_enter_cmd_xip()</code>)なので、<code>'C', 'X'</code>を渡す。関数のポインタが返ってきて、それを呼び出せばフラッシュROMとSSIはXIPモードになる: </p> -<pre><code>struct circle { - float ppx, ppy; // previous position (center) - float px, py; // current position (center) - float vx, vy; // velocity - int r; // radius - int m; // mass -}; +<pre><code>setup_xip: + ldr r3, rom_base -int -circle_test_collision(struct circle *c1, struct circle *c2) -{ - return (c1->px - c2->px) * (c1->px - c2->px) + - (c1->py - c2->py) * (c1->py - c2->py) < - (c1->r + c2->r) * (c1->r + c2->r); -} + ldrh r0, [r3, #0x14] // rom_func_table + ldr r1, =('C' | 'X' &lt;&lt; 8) // _flash_enter_cmd_xip() + ldrh r2, [r3, #0x18] // rom_table_lookup + blx r2 + blx r0 +/* ... */ +rom_base: + .word 0x00000000 </code></pre> <p> -衝突後は前回と同じく弾性衝突として処理した。四角形とは違い、衝突方向の場合分けが不要なので楽である。 -</p> -<pre><code> -void -circle_handle_collision_mm(struct circle *c1, struct circle *c2) -{ - if (!circle_test_collision(c1, c2)) - return; - - float col_px = c2->px - c1->px; - float col_py = c2->py - c1->py; - float col_pr = sqrtf(col_px * col_px + col_py * col_py); - col_px /= col_pr; - col_py /= col_pr; - - c1->px = c1->px - col_px / 2; - c1->py = c1->py - col_py / 2; - c2->px = c2->px + col_px / 2; - c2->py = c2->py + col_py / 2; -} - -void -circle_handle_collision_elastic(struct circle *c1, struct circle *c2) -{ - if(!circle_test_collision(c1, c2)) - return; - - float col_px = c2->px - c1->px; - float col_py = c2->py - c1->py; - float col_pr = sqrtf(col_px * col_px + col_py * col_py); - col_px /= col_pr; - col_py /= col_pr; - float nor_px = col_py; - float nor_py = -col_px; - - float m1 = c1->m; - float m2 = c2->m; - - float col_1v = c1->vx * col_px + c1->vy * col_py; - float col_2v = c2->vx * col_px + c2->vy * col_py; - - float col_1vxn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_px; - float col_1vyn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_py; - float col_2vxn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_px; - float col_2vyn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_py; +XIPの設定が完了すれば、次はメインのプログラムを実行するための準備である。エントリーポイントの指定、スタックポインタの初期値の設定、ベクターテーブルの設定である。Armのマニュアル<sup>[7]</sup>によると、初期スタックポインタとエントリーポイントはベクターテーブルの<code>0x0</code>バイト目と<code>0x4</code>バイト目に書くことになっている:</p> +<blockquote cite="https://developer.arm.com/documentation/ddi0419/c/System-Level-Architecture/System-Level-Programmers--Model/ARMv6-M-exception-model/Exception-number-definition"> +<table> +<caption> +Table 7.3. Exception numbers +</caption><colgroup><col><col></colgroup><thead><tr><th>Exception number</th><th>Exception</th></tr></thead><tbody><tr><td>1</td><td>Reset</td></tr><tr><td>2</td><td>NMI</td></tr><tr><td>3</td><td>HardFault</td></tr><tr><td>4-10</td><td>Reserved</td></tr><tr><td>11</td><td>SVCall</td></tr><tr><td>12-13</td><td>Reserved</td></tr><tr><td>14</td><td>PendSV</td></tr><tr><td>15</td><td>SysTick, optional</td></tr><tr><td>16</td><td>External Interrupt(0)</td></tr><tr><td>...</td><td>...</td></tr><tr><td>16 + N</td><td>External Interrupt(N)</td></tr></tbody> +</table> +</blockquote> - float nor_1vx = nor_px * (c1->vx * nor_px + c1->vy * nor_py); - float nor_1vy = nor_py * (c1->vx * nor_px + c1->vy * nor_py); - float nor_2vx = nor_px * (c2->vx * nor_px + c2->vy * nor_py); - float nor_2vy = nor_py * (c2->vx * nor_px + c2->vy * nor_py); +<blockquote cite="https://developer.arm.com/documentation/ddi0419/c/System-Level-Architecture/System-Level-Programmers--Model/ARMv6-M-exception-model/The-vector-table"> +<table> +<caption> +Table 7.4. Vector table format +</caption><colgroup><col><col></colgroup><thead><tr><th>Word offset in table</th><th>Description, for all pointer address values</th></tr></thead><tbody><tr><td>0</td><td>SP_main. This is the reset value of the Main stack pointer.</td></tr><tr><td>Exception Number</td><td>Exception using that Exception Number</td></tr></tbody> +</table> +</blockquote> +<p> +また、ベクターテーブルはメインのプログラムの先頭に置くことにする。メインのプログラムはFlash Second Stageが占有する256バイトの直後、フラッシュROMの257バイト目から配置することにする。RP2040のベクターテーブルはM0PLUS: VTOR(<code>0xe0000000 + 0xed08</code>)というレジスタに書き込むことで設定する。以上をまとめると以下のコードになる:</p> +<pre><code> ldr r0, flash_main + ldr r1, m0plus_vtor + str r0, [r1, #0] // vector table + ldr r1, [r0, #4] // entry point + ldr r0, [r0, #0] // stack pointer + mov sp, r0 + bx r1 - c1->vx = col_1vxn + nor_1vx; - c1->vy = col_1vyn + nor_1vy; - c2->vx = col_2vxn + nor_2vx; - c2->vy = col_2vyn + nor_2vy; +/* ... */ - circle_handle_collision_mm(c1, c2); -} +flash_main: + .word 0x10000000 + 0x100 +m0plus_vtor: + .word 0xe0000000 + 0xed08 </code></pre> +<p>なお以上のコードは<code>.boot2</code>という名前のセクションにしてある。 +</p> -<h2>完成品</h2> +<h2>メインのコード(<code>main.s</code>)</h2> +<h3>ベクターテーブル</h3> <p> -<a href="https://git.mtkn.jp/xlib_playground/file/ex5/ex5.c.html">git</a> -</p> +メインのコードの最初には上で説明したベクターテーブルを配置する。ここでは割り込みの処理は考えないので、初期スタックポインタとエントリーポイントだけである。初期スタックポインタはSRAMの最後?(<code>0x20040000</code>)、エントリーポイントはエントリーポイントのラベルを用いて設定した。</p> +<pre><code>vectors: + .word 0x20040000 // initial SP + .word (reset+1) +</code></pre> <p> -<video controls> -<source src="videos/ex5.webm" type="video/webm"> -</video> +<code>reset</code>ラベルに<code>1</code>を足しているのはRP2040がThumbモードのみに対応しているからである。ArmのCPUはArmモードとThumbモードがあり、Armモードは32ビットの命令で高機能。Thumbモードは16ビットの命令(一部32ビット)でコンパクトである。どちらのモードでも命令は2の倍数のアドレスに並ぶことになる。そのためジャンブ命令のジャンプ先のアドレスの最下位ビットは常に0である。この最下位ビットはジャンプ先のモードを示す為に利用される。両方のモードに対応したCPUではジャンプ先のアドレスの最下位ビットが0ならArmモード、1ならThumbモードに切り替わる。ブランチ命令のオペランド等は多分アセンブラがいい感じにしてくれるので単にラベルを書けば動く。ベクターテーブルのこの部分は自分で足す必要があるみたい。あんまりちゃんと調べてないのでマニュアル読んでや。</p> +<p> +この部分のセクション名は<code>.vectors</code>である。 </p> -<h2>参考</h2> -<ul> -<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> -</ul> +<h3>GPIOの設定</h3> <p> -次の記事: <a href="xlib_playground6.html">Xlibで遊んでみる6</a> +電源投入直後、RP2040の周辺機器はリセット状態になっている。まずは今回利用するGPIOのリセット状態を解除する必要がある。データシートの「2.14. Subsystem Resets」には以下のように書かれている: </p> -]]></description> -</item> -<item> -<title>Xlibで遊んでみる4</title> -<link>https://www.mtkn.jp/computer/xlib_playground4.html</link> -<guid>https://www.mtkn.jp/computer/xlib_playground4.html</guid> -<pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> -<description><![CDATA[<h1>Xlibで遊んでみる4</h1> -<time>2023-01-02</time> - +<blockquote cite="https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf"> <p> -前回: <a href="xlib_playground3.html">Xlibで遊んでみる3</a> +Every peripheral reset by the reset controller is held in reset at power-up. +It is up to software to deassert the reset of peripherals it intends to use. </p> +</blockquote> <p> -言語: C言語<br /> -ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> +リセット状態を解除するには、RESETS_BASE(<code>0x4000c000</code>)から<code>0x0</code>バイト目のRESETS: RESETレジスタのうち利用したい周辺機器のビットを<code>0x0</code>にすればいい。 +GPIOはIO Bank 0なので(これ明記されてなくない?)、RESETS: RESETレジスタのIO_BANK0(5番ビット)を<code>0x0</code>にする。 +</p> +<h4>レジスタのアトミックなクリア</h4> +<p> +RESETS: RESETレジスタのうち5番ビットだけを<code>0x0</code>にしたい。この時、まずこのレジスタを読み込んでから<code>~(1 &lt;&lt; 5)</code>と論理積を取って同レジスタに書き戻してもいいのだが、RP2040にはこれを一回の<code>str</code>でしかもアトミックにできる機能が用意されている。今回の場合アトミックかどうかは関係ないと思うけど。</p> +<p> +各レジスタには4個のアドレスが割り当てられている。データシートの各章のList of Registersに記載されているアドレスは通常の読み書きができる。そのアドレスに<code>0x1000</code>を足したものにアクセスするとアトミックなXORが、<code>0x2000</code>を足したものはアトミックなセットが、<code>0x3000</code>を足したものはアトミックなクリアができる。つまりレジスタのアドレスに<code>0x3000</code>を足したものに、<code>0x1 &lt;&lt; 5</code>を<code>str</code>すれば5番目のビットだけ<code>0x0</code>にして、他のビットは変更されない。逆に指定したビットだけ立てて他を触らない場合は<code>0x2000</code>を、あるいは指定したビットだけトグルしたい場合は<code>0x1000</code>を足したアドレスにアクセスすればいい。</p> +<h4>リセット状態の確認</h4> +<p>リセットの解除はすぐに完了するわけではないようである。リセットの解除が完了したかどうか確認するにはRESETS: RESET_DONEレジスタ(RESETS_BASEから<code>0x8</code>バイト目)の該当するビット(ここでは5番目のビット)を読む。この値が<code>0x1</code>であればリセットの解除が完了している。<code>0x0</code>であれば処理が進行中なので<code>0x1</code>が返ってくるまで繰り返し読み込んで<code>0x0</code>になるまで待機する。ところでこのレジスタはリセットの解除が完了したかどうか確かめるものなので、RESET_DONEという名前はどうなん? +<p> +以上から、GPIOのリセットを解除するのは以下のコード: </p> +<pre><code>reset: + // unreset gpio + mov r0, #1 + lsl r0, r0, #5 // io_bank0 + ldr r3, resets_base + ldr r1, atomic_clr + str r0, [r3, r1] // RESETS: RESET +reset_chk: + ldr r1, [r3, #0x8] // RESETS: RESET_DONE + tst r0, r1 + beq reset_chk -<h2>衝突判定とその処理</h2> +/* ... */ + +atomic_clr: + .word 0x00003000 +resets_base: + .word 0x4000c000 +</code></pre> + +<h3>GPIOの機能の選択</h3> +<p>RP2040のGPIOにはそれぞれ複数の機能が用意されていて、どれを使うかはソフトウェアから選択できる。利用できる機能の一覧と各機能の説明はデータシートの「2.19.2 Function Select」に詳しく書いてある。ここではGPIO25番のピンをSIO(Single-cycle IO)として利用する。同じCPUが載っているRaspberry Pi PicoはGPIO25番にLEDが半田付けされている。25番にしたのはこれに合わせるためである。他のピンでもいい。GPIOに1か0を印加するだけならこのSIOを使うみたいである。Single-cycleはCPUから操作したときに1クロックでその操作が完了するという意味らしい(本当か)。SIOの詳しい説明はデータシートの「2.3.1 SIO」にある。</p> <p> -これまでは一つの四角形だけを描画していたが、今回は複数の四角形を作成して動かしてみた。ランダムな場所にランダムな運動量で動かして、他のものやウィンドウの縁とぶつかったら跳ね返るようにした。</p> +GPIO25番の機能を選択するにはIO_BANK0_BASE(<code>0x40014000</code>)から<code>0xcc</code>番目のGPIO25_CTRLレジスタの下位5ビットに、該当する機能の番号を書き込めばいい。データシートの「2.19.2 Function Select」にある表を見ると、GPIO25番のSIOは5である:</p> +<pre><code> // set gpio functions + ldr r3, io_bank0_base + mov r0, #5 // sio + mov r1, #0xcc + str r0, [r3, r1] // IO_BANK0: GPIO25_CTRL + +/* ... */ + +io_bank0_base: + .word 0x40014000 +</code></pre> + +<h3>GPIOの出力を有効化</h3> <p> -回転しない四角形どうしの衝突判定は簡単である。x軸方向とy軸方向の両方に重なりがあれば衝突している: +GPIO25番がSIOになったので、次にこのピンからの出力を有効化する。既定値では出力は無効になっている。ハイインピーダンスってことなのかな?出力を有効にするには、SIO_BASE(<code>0xd0000000</code>)から<code>0x24</code>バイト目のSIO: GPIO_OEレジスタの該当するビット(25番のピンなので25番ビット)を<code>0x1</code>にする: </p> -<pre><code>struct square { - float ppx, ppy; // previous position - float px, py; // current position - float vx, vy; // velocity - int w, h; // width and height -}; +<pre><code> + // enable gpio output + ldr r3, sio_base + mov r0, #1 + lsl r0, r0, #25 // gpio25 + str r0, [r3, #0x24] // SIO: GPIO_OE -int -test_collision(struct square *s1, struct square* s2) -{ - return s1->px < s2->px + s2->w && s2->px < s1->px + s1->w && - s2->py < s1->py + s1->h && s1->py < s2->py + s2->h; -} +/* ... */ + +sio_base: + .word 0xd0000000 </code></pre> +<h3>LEDの点滅</h3> +<p>以上でGPIOの設定は完了したので、あとは実際にLEDに電圧を掛けるだけである。レジスタのアドレスに<code>0x1000</code>を足したものに書き込むとアトミックなレジスタのXORができると書いたが、SIOはこの機能がサポートされていないようである。データシートの「2.1.2 Atomic Register Access」に、 +</p> +<blockquote cite="https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf"> <p> -衝突後の処理は多少めんどくさかった。衝突した時は既にめりこんでいるので、まずはそれぞれをめりこんだ距離の半分ずつずらして衝突を解消するようにした。この際、x軸方向にぶつかったのか、y軸方向にぶつかったのかで、それぞれの軸方向にひっぺがすようにしている。二つの四角形の各軸に関するめりこんだ距離<code>lapx</code>、<code>lapy</code>と各軸に関する相対速度<code>rel_vx</code>、<code>rel_vy</code>の比を比べればどちらの軸方向にぶつかったかが分かるはずである、多分 : +The SIO (Section 2.3.1), a single-cycle IO block attached directly to the cores' +IO ports, does <strong>not</strong> support atomic accesses at the bus level, +although some individual registers (e.g. GPIO) have set/clear/xor aliases. </p> -<pre><code>void -handle_collision_mm(struct square *s1, struct square *s2) +</blockquote> +<p> +と書かれている。そのかわりここにも書かれている通り、SIOの一部のレジスタにはアトミックなセット/クリア/XORをするためのレジスタが用意されている。ここではLEDを点滅させるためにGPIOの出力をトグルしたいのでXOR用のレジスタを使う。SIO_BASE(<code>0xd0000000</code>)から<code>0x1c</code>バイト目のSIO: GPIO_OUT_XORレジスタがそれである。このレジスタの25番ビットに<code>0x1</code>を書き込めばいい。出力をトグルした後は少し間をおいて同じことを繰り返す。間をおくためにここでは適当な数値を1づつ減らしていって0になったら返る関数<code>delay</code>を作った。タイマーと割り込みを使ったほうが消費電力等で優位なようだが、面倒なのでとりあえずこれで:</p> + +<pre><code> // blink led on gpio25 + ldr r4, sio_base + mov r5, r0 // r0 = 1 &lt;&lt; 25 +loop: + str r5, [r4, #0x1c] // SIO: GPIO_OUT_XOR + bl delay + b loop + +delay: + mov r0, #1 + lsl r0, r0, #20 +delay_loop: + sub r0, r0, #1 + bne delay_loop + bx lr + +/* ... */ + +sio_base: + .word 0xd0000000 +</code></pre> +<p>なお以上のコードは<code>.text</code>セクションである。</p> + +<h2>リンカスクリプト</h2> +<p> +以上のコードには<code>.boot2</code>、<code>.vectors</code>、<code>.text</code>の3つのセクションが含まれる。<code>.boot2</code>はフラッシュの先頭から256(<code>0x100</code>)バイト目まで、<code>.vectors</code>と<code>.text</code>はその後ろに続くように配置する: +<pre><code>MEMORY { - if (!test_collision(s1, s2)) - return; + FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k +} - float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px); - float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py); - float rel_vx = max(s1->vx - s2->vx, s2->vx - s1->vx); - float rel_vy = max(s1->vy - s2->vy, s2->vy - s1->vy); +SECTIONS +{ + .boot2 : { + *(.boot2) + . = 0x100; + } > FLASH - if (lapx / rel_vx < lapy / rel_vy) { - if (s1->px + s1->w < s2->px + s2->w / 2) { - s1->px -= lapx / 2; - s2->px += lapx / 2; - } else { - s1->px += lapx / 2; - s2->px -= lapx / 2; - } - } else { - if (s1->py + s1->h < s2->py + s2->h / 2) { - s1->py -= lapy / 2; - s2->py += lapy / 2; - } else { - s1->py += lapy / 2; - s2->py -= lapy / 2; - } - } + .text : { + *(.vectors) + *(.text) + } > FLASH } -</pre></code> +</code></pre> + +<h2>Makefile</h2> <p> -衝突は弾性衝突として、衝突したそれぞれの四角形の速度を更新した。質量は四角形の面積として計算している。衝突後の速度はエネルギー保存則と運動量保存則から導いたのでしんどかった。 +以上のソースコードは以下のように配置している: </p> -<pre><code>void -handle_collision_elastic(struct square *s1, struct square *s2) -{ - if(!test_collision(s1, s2)) - return; +<pre><code>rp2040 +├── ex1 +│   ├── Makefile +│   ├── boot2.s +│   ├── main.s +│   └── memmap.ld +└── tools + ├── Makefile + ├── bin2uf2.c + └── bincrc.c +</code></pre> +<p> +toolsディレクトリのMakefileは同じディレクトリのソースファイルを<code>$(CC)</code>でコンパイルするだけのものである(個人的な趣味で<code>tcc</code>を使っている)。ex1ディレクトリのMakefileは以下の通り: +</p> +<pre><code>AS = arm-none-eabi-as +LD = arm-none-eabi-ld +OBJCOPY = arm-none-eabi-objcopy +BINCRC = ../tools/bincrc +BIN2UF2 = ../tools/bin2uf2 - float v1, v2; - float m1 = s1->w * s1->h; - float m2 = s2->w * s2->h; +MCPU = -mcpu=cortex-m0plus +ASFLAGS = $(MCPU) +CFLAGS = $(MCPU) -ffreestanding -nostartfiles -O0 -fpic -mthumb -c +LDFLAGS = --no-relax -nostdlib - float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px); - float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py); +all: tools led.uf2 - if (lapx < lapy) { - v1 = s1->vx; - v2 = s2->vx; - s1->vx = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1; - s2->vx = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2; - } else { - v1 = s1->vy; - v2 = s2->vy; - s1->vy = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1; - s2->vy = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2; - } +clean: + rm -f *.o *.elf *.uf2 *.bin + cd ../tools &amp;&amp; make clean - handle_collision_mm(s1, s2); -} -</code></pre> +.s.o: + $(AS) $(ASFLAGS) -o $@ $&lt; -<h2>サブティック</h2> -<p> -この名前が適切かどうか分からないが、前のフレームから次のフレームまでの時間をさらに何等分かして衝突判定の制度を上げた(マクロは括弧でかこって分かりにくいバグを防げとどこかに書いていたのでそうすることにした): -</p> -<pre><code>#define SUB_TIC (4) +led.elf: boot2.o main.o memmap.ld + $(LD) $(LDFLAGS) -o $@ -T memmap.ld boot2.o main.o -void -game_play(void) -{ - /* ... */ - while (next_menu == GAME_PLAY) { - /* ... */ - for (int j = 0; j < SUB_TICK; j++) { - for (int i = 0; i < NUM_SQUARE; i++) - next_tick(&square[i], 1000 * 1000 * 1000 / FPS / SUB_TICK); +led.bin: led.elf + $(OBJCOPY) -O binary led.elf $@ - for (int i = 0; i < NUM_SQUARE; i++) - for (int j = i + 1; j < NUM_SQUARE; j++) { - handle_collision_elastic(&square[i], &square[j]); - /* ... */ - } - /* ... */ - } - /* ... */ - } - /* ... */ -} +led.uf2: led.bin + $(BINCRC) led.bin led_crc.bin + $(BIN2UF2) led_crc.bin $@ + +flash: all + mount /dev/disk/by-label/RPI-RP2 /mnt + cp led.uf2 /mnt + +tools: + cd ../tools &amp;&amp; make </code></pre> -<h2>完成品</h2> <p> -<a href="https://git.mtkn.jp/xlib_playground/file/ex4/ex4.c.html">git</a> -</p> +RP2040のボードをUSBデバイスモードでLinuxのパソコンに接続し、ex1ディレクトリで</p> +<pre><code>$ make +# make flash +</code></pre> <p> -<video controls> -<source src="videos/ex4.webm" type="video/webm"> -</video> +とすればプログラムがRP2040のボードに書き込まれて実行が開始される。</p> + +<h2>最後に</h2> +<p> +光あれ。 </p> <h2>参考</h2> <ul> -<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> +<li> +[1] Hennesy, J. L. and Patterson, D. A. 2017. Computer Organization And Design RISC-V Edition. +</li> +<li> +[2] <a href="https://akizukidenshi.com/catalog/g/gK-17542/">RP2040マイコンボードキット.秋月電子通商</a> +</li> +<li> +[3] <a href="https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf">RP2040 Datasheet.Raspberry Pi Foundation</a> +</li> +<li> +[4] <a href="https://github.com/raspberrypi/pico-sdk">pico-sdk.github</a> +</li> +<li> +[5] <a href="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB">巡回冗長検査.Wikipedia</a> +</li> +<li> +[6] <a href="https://github.com/microsoft/uf2">USB Flashing Format (UF2).GitHub</a> +</li> +<li> +[7] <a href="https://developer.arm.com/documentation/ddi0419/c/">ARMv6-M Architecture Reference Manual</a> +</li> </ul> -<p> -次の記事: <a href="xlib_playground5.html">Xlibで遊んでみる5</a> -</p> ]]></description> </item> <item> -<title>Xlibで遊んでみる3</title> -<link>https://www.mtkn.jp/computer/xlib_playground3.html</link> -<guid>https://www.mtkn.jp/computer/xlib_playground3.html</guid> -<pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> -<description><![CDATA[<h1>Xlibで遊んでみる3</h1> -<time>2023-01-02</time> - -<p> -前回: <a href="xlib_playground2.html">Xlibで遊んでみる2</a> -</p> -<p> -言語: C言語<br /> -ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> -</p> - -<h2>画面サイズの変更</h2> -<p> -画面サイズが変更された時に表示している四角形が画面の外側に出ないようにした。<code>XGetWindowAttributes()</code>で画面の情報を取得し、グローバル変数の<code>win_width</code>と<code>win_height</code>に幅と高さをそれぞれ代入して<code>next_tick()</code>で四角形の位置を画面に収まるようにしている: -</p> -<pre><code>int win_width, win_height; - -void -receive_events(int key_state[]) -{ - XEvent event; - XWindowAttributes wattr; - - while (XPending(display) > 0) { - XNextEvent(display, &event); - switch (event.type) { - case Expose: { - XGetWindowAttributes(display, window, &wattr); - win_width = wattr.width; - win_height = wattr.height; - } break; - /* ... */ - } - } -} - -void -next_tick(long ndt) // nano second -{ - px = px + vx * ndt / 1000 / 1000 / 1000; - py = py + vy * ndt / 1000 / 1000 / 1000; - // bind within the window - if (px < 0) - px = 0; - if (win_width < px + width) - px = win_width - width; - if (py < 0) - py = 0; - if (win_height < py + height) - py = win_height - height; -} -</code></pre> - -<h2>メニュー画面の実装</h2> -<p> -ゲームのようなものを作るうえでメニュー画面とその推移が必要である。ここではグローバル変数<code>next_menu</code>に現在のメニューを保存することにした。それぞれのメニューはそれぞれ関数として記述し、他のメニューに推移する必要が生じたときに<code>next_menu</code>を変更するようにした: -</p> -<pre><code>enum next_menu { - START_MENU, - GAME_PLAY, - GAME_OVER, - QUIT, -}; - -int next_menu = START_MENU; +<title>使用しているハードウェア、ソフトウェア</title> +<link>https://www.mtkn.jp/computer/what-i-use.html</link> +<guid>https://www.mtkn.jp/computer/what-i-use.html</guid> +<pubDate>Tue, 2 May 2023 00:00:00 +0900</pubDate> +<description><![CDATA[<h1>使用しているハードウェア、ソフトウェア</h1> +<time>2023-05-02</time>更新<br> +<time>2021-12-13</time>作成 +<h2>ノートパソコン</h2> +<p>メインのパソコン。</p> +<dl> +<dt>ハードウェア: Macbook Air 2013</dt> +<dd>ThinkPad辞めた。ファンがあまりにもうるさい。ThinkPadの前に使ってたMacbook Airを引っ張り出してバッテリー交換して使ってみたらファンがめっちゃ静か。多分ほぼ回ってない。M1 Macbook Airが欲しくなってきた。</dd> +<dt>OS: Arch Linux</dt> +<dd>本当はOpenBSDがいいんやけどMacbook AirだとWi-Fiも使えやんしいろいろサポートが悪いので...</dd> -void -start_menu(void) -{ - XEvent event; - char *menu_char_q = "press q to quit."; - char *menu_char_s = "press <space> to start."; +<dt>Window Manager: <a href="https://git.mtkn.jp/dwm">dwm</a></dt> - XClearArea(display, window, - 0, 0, // position - win_width, win_height, // width and height - False); - XDrawString(display, window, gc, - win_width/2 - strlen(menu_char_q)/2, win_height/2, - menu_char_q, strlen(menu_char_q)); - XDrawString(display, window, gc, - win_width/2 - strlen(menu_char_s)/2, win_height/2 + 20, - menu_char_s, strlen(menu_char_s)); +<dt>Terminal: <a href="https://git.mtkn.jp/st">st</a></dt> - while (next_menu == START_MENU) { - XNextEvent(display, &event); - switch (event.type) { - case Expose: { - XDrawString(display, window, gc, - win_width/2 - strlen(menu_char_q)/2, - win_height/2, - menu_char_q, strlen(menu_char_q)); - XDrawString(display, window, gc, - win_width/2 - strlen(menu_char_s)/2, - win_height/2 + 20, - menu_char_s, strlen(menu_char_s)); +<dt>Text Editor: nvi</dt> +<dd>vimは辞めた。OpenBSDにあったnviが丁度いい。日本語を使うのでUTF8に対応したnvi2を使っている。Arch Linuxだとちょっと使い勝手が違う。コマンド履歴が編集できないのが不便である。Samとかacmeとか使ってみたいけど日本語入力できやんのはちょっと...</dd> - } break; - case KeyPress: { - switch (XLookupKeysym(&event.xkey, 0)) { - case 'q': - next_menu = QUIT; - break; - case ' ': - next_menu = GAME_PLAY; - break; - default: - break; - } - } break; - case ClientMessage: { - if ((Atom) event.xclient.data.l[0] == wm_delete_window) { - next_menu = QUIT; - } - } break; - default: - break; - } - } -} +<dt>Browser: firefox</dt> +<dd>もうちょっとましなのないんかな。UIころころ変わるし、重いし、嫌い。JavaScriptがないと困るので仕方なく使っているが...</dd> -int -main(void) -{ - setup(); - while (next_menu != QUIT){ - switch (next_menu){ - case START_MENU: - start_menu(); - break; - case GAME_PLAY: - game_play(); - break; - case GAME_OVER: - game_over(); - break; - default: - break; - } - } +<dt>Mail Cdtent: neomutt</dt> +</dl> - cleanup(); - return 0; -} -</code></pre> -<p><code>main()</code>関数がめっちゃすっきりした。</p> +<h2>デスクトップ</h2> +<p>学生のときに組んだ。無駄にハイスペック。この上RTX2060も積んでたが、OpenBSDで使えないので解雇した。あんまり使ってない。</p> +<dl> +<dt>マザーボード: ASRock Z390 Pro4</dt> +<dt>CPU: Intel Core i7-9700K</dt> +<dt>メモリ: センチュリーマイクロ 8GB * 2</dt> +<dd>国産</dd> +<dt>ストレージ: KimMiDi SSD 256GB</dt> +<dd>ThinkPad買ったときについてきたやつ。</dd> +<dt>モニタ: Eizo FlexScan EV2451</dt> +<dd>綺麗やけど質量が大きい。</dd> +<dt>OS: OpenBSD</dt> +<dd>いい</dd> +<dt>ソフト: ノートパソコンと同じ</dt> +</dl> -<h2>完成品</h2> -<p> -<a href="https://git.mtkn.jp/xlib_playground/file/ex3/ex3.c.html">git</a> -</p> +<h2>家のサーバー</h2> <p> -<video controls> -<source src="videos/ex3.webm" type="video/webm"> -</video> +バックアップ用 </p> +<dl> +<dt>ハードウェア: Dell D520</dt> +<dd>おじいちゃんの家にころがってたのをもらってきた。</dd> +<dt>OS: OpenBSD</dt> +</dl> -<h2>参考</h2> -<ul> -<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> -</ul> -<p> -次の記事: <a href="xlib_playground4.html">Xlibで遊んでみる4</a> -</p> +<h2>ウェブサーバー</h2> +<p>このウェブページ用</p> +<dl> +<dt>VPS: さくらのVPS</dt> +<dd>ちょっと高い(7078円/12ヶ月)。OpenBSDを入れられる。</dd> +<dt>OS: OpenBSD</dt> +<dt>httpサーバー: Openbsd httpd</dt> +<dd>manが分かりやすい。</dd> +<dt>smtpサーバー: OpenSMTPD</dt> +<dd>manが分かりやすい。</dd> +<dt>imapサーバー: dovecot</dt> +<dd>manはあんまり分かり易くない。<dd> +</dl> + +<h2>理想</h2> +<dl> +<dt>CPU: RISC-V</dt> +<dd>はやく家庭用コンピュータの世界に来てほしい</dd> +<dt>ファン: レス</dt> +<dd>静音性は優先度がかなり高い。</dd> +<dt>メモリ: 8GB</dt> +<dd>そんないらん</dd> +<dt>モニター: 60fpsでるカラーの電子ペーパー</dt> +<dt>キーボード: PFU製</dt> +<dd>macbook airに戻っても特にストレスないからキーストロークはそんなにいらんかな</dd> +<dt>バッテリー: 24時間くらい</dt> +<dt>OS: Plan9かOpenBSD</dt> +<dd>ハードウェアは全部ドキュメント公開してくれ</dd> +</dl> ]]></description> </item> <item> -<title>Xlibで遊んでみる2</title> -<link>https://www.mtkn.jp/computer/xlib_playground2.html</link> -<guid>https://www.mtkn.jp/computer/xlib_playground2.html</guid> +<title>Xlibで遊んでみる6</title> +<link>https://www.mtkn.jp/computer/xlib_playground6.html</link> +<guid>https://www.mtkn.jp/computer/xlib_playground6.html</guid> <pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> -<description><![CDATA[<h1>Xlibで遊んでみる2</h1> -<time>2022-12-22</time> +<description><![CDATA[<h1>Xlibで遊んでみる6</h1> +<time>2023-01-25</time> -<p>前回: <a href="xlib_playground1.html">Xlibで遊んでみる1</a></p> -<p>言語はC言語である。ソースコードは<a href="https://git.mtkn.jp/xlib_playground">ここ</a>にある。 +<p> +前回: <a href="xlib_playground5.html">Xlibで遊んでみる5</a> </p> - -<h2>FPSの固定</h2> -<p>前のフレームからの経過時間を計測して<code>1.0/FPS</code>を越えるまで待機させる。このときに<code>nanosleep()</code>を使うとなぜか上手くいかなかった。ナノ秒単位で処理できそうな名前なのに使えない。多分OSのコンテクストスイッチがどうとかいう話やと思う。知らんけど。組み込みとかで使うんかな? +<p> +言語: C言語<br /> +ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> </p> +<h2>ワールドマップの作成</h2> <p> -とりあえず<code>while</code>ループの中でひたすら時刻を読んでいる。リソースの無駄遣いではないのだろうか: +ゲームのワールドマップを作製した。ここでは文字列として登録した。なにもないところは「<code>.</code>」、ブロックの場所は「<code>b</code>」、プレーヤーは「<code>p</code>」とした: </p> -<pre><code>#defin FPS 60 - -int -main(void) -{ - long t0, t1, dt; - int fps_count; - - clock_gettime(CLOCK_MONOTONIC, &ts); - t0 = ts.tv_nsec; - - while (!quit) { - // fix fps - dt = 0; - while (dt < 1.0 * 1000 * 1000 * 1000 / FPS){ - clock_gettime(CLOCK_MONOTONIC, &ts); - t1 = ts.tv_nsec; - dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000; - } - // count fps. - fps_count++; - if (t1 < t0){ - printf("fps: %u\n", fps_count); - fps_count = 0; - } - clock_gettime(CLOCK_MONOTONIC, &ts); - t0 = ts.tv_nsec; - } -} +<pre><code>char worldmap[WORLD_WIDTH * WORLD_HEIGHT + 1] = +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"........b......................................................................." +"................................................................................" +"................................................................................" +"....b..........................................................................." +"................................................................................" +"................b..............................................................." +"..........................................................b..........b.........." +"................................................................................" +".......................b........................................................" +"...........................................b...................................." +"...........................................b...................................." +"................................................................................" +"..................b............................................................." +"................................................................................" +"...........................................b...................................." +"................................................................................" +"................................................................................" +"...........................b...................................................." +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"....................................bbbbbbbbbb.................................." +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"..............................................bbbbbbbbbb........................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"....................................bbbbbbbbbb.................................." +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"..........................bbbbbbbbbb............................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................bbbbbbbbbb......................................................" +"................................................................................" +"................................................................................" +"...p............................................................................" +"bbbbbbbbbbbbbbbbbbbbbbbbb.......bbbbbbbbbbbbbbbbbbbbbbbb...bbbbbbbbbbbbbbbbbbbbb" +"........................b.......b......................b...b...................." +"........................b.......b......................b...b...................." +"........................b.......b......................b...b...................." +"........................b.......b......................b...b...................."; </code></pre> -<p> -時刻は<code>clock_gettime()</code>で測定して1秒未満の部分: <code>tv_nsec</code>だけを利用している。<code>tv_nsec</code>はナノ秒ナノで、10<sup>9</sup>を掛けている。<code>dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000</code>で前回の時刻と現在の時刻の少数部分を比較している。繰り上がりがあれば前回の時刻よりも現在の時刻の方が小さくなるので1秒足すことで調整している。</p> -<p> -FPSの計測の部分は、フレーム毎に<code>fps_count</code>を1ずつ増やし、ナノ秒が繰り上がった時点での<code>fps_count</code>を表示している。</p> -<p> -あまり正確な方法ではないように思うが、コンパクトにまとまったのではないだろうか。</p> -<h2>キーボード入力の処理</h2> -<p>キーボードからの入力を受け取る:</p> -<pre><code>XSelectInput(display, window, - ExposureMask|KeyPressMask|KeyReleaseMask); -</code></pre> -<p>ここではキーボードのキーを押した時と離した時に<code>XEvent</code>の通知を受け取るように設定した。 -</p> -<p> -<code>XNextEvent()</code>からひとつずつ入力を受け取ると、複数のキーが同時に押された時にうまく処理できなかったので、押されているキーを配列に保存しておくことにした:</p> -<pre><code>enum Keys { - Key_D, - Key_S, - Key_A, - Key_W, - Key_Space, - Num_Key, //number of keys in this enum -}; -enum Key_State { - Key_Up, - Key_Down, +<h2>プレイヤーの作成</h2> +<p>プレイヤーには重力をかけたいので、まずは四角形に加速度を追加:</p> +<pre><code>struct rect { + float ppx, ppy; + float px, py; + float vx, vy; + float ax, ay; // acceleration + int w, h; + int m; }; - -int key_state[Num_Key]; </code></pre> +<p>ワールドマップを読み込み、その際にプレイヤーに重力を付加:</p> +<pre><code>struct rect block[NUM_RECT]; +struct rect player; -<p> -入力の処理は<code>handle_inputs()</code>関数内で行なう。<code>A</code>、<code>S</code>、<code>D</code>、<code>W</code>のうちどれかのキーが押されているとそれぞれ左、下、右、上方向に速度を加算するようにした。また、<code>Q</code>が押されるか、windowが破壊されると<code>quit</code>フラグを<code>1</code>にしてメインループから抜けるようにしている:</p> -<pre><code>int quit; - -void -handle_inputs(void) -{ - XEvent event; - while (XPending(display) > 0) { - XNextEvent(display, &event); - switch (event.type) { - case KeyPress: { - switch (XLookupKeysym(&event.xkey, 0)) { - case 'q': - quit = 1; - break; - case 'd': - key_state[Key_D] = Key_Down; - break; - case 'a': - key_state[Key_A] = Key_Down; - break; - case 'w': - key_state[Key_W] = Key_Down; - break; - case 's': - key_state[Key_S] = Key_Down; - break; - default: - break; - } - } break; - case KeyRelease: { - switch (XLookupKeysym(&event.xkey, 0)) { - case 'd': - key_state[Key_D] = Key_Up; - break; - case 'a': - key_state[Key_A] = Key_Up; - break; - case 'w': - key_state[Key_W] = Key_Up; - break; - - case 's': - key_state[Key_S] = Key_Up; - break; - default: - break; - } - } break; - case ClientMessage: { - if ((Atom) event.xclient.data.l[0] == wm_delete_window) { - quit = 1; - } - } break; - default: - break; - } - } +/* ... */ - vx = vy = 0; - if (key_state[Key_D] == Key_Down) - vx += 300; - if (key_state[Key_A] == Key_Down) - vx += -300; - if (key_state[Key_S] == Key_Down) - vy += 300; - if (key_state[Key_W] == Key_Down) - vy += -300; -} + int bi = 0; + for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) { + if (world_map[i] == 'b') { + block[bi].ppx = block[bi].px = i % WORLD_WIDTH * BLOCK_SIZE; + block[bi].ppy = block[bi].py = i / WORLD_WIDTH * BLOCK_SIZE; + block[bi].ax = 0; + block[bi].ay = 0; + block[bi].vx = 0; + block[bi].vy = 0; + block[bi].w = block[bi].h = BLOCK_SIZE; + block[bi].m = block[bi].w * block[bi].h; + bi++; + } else if (world_map[i] == 'p') { + player.ppx = player.px = i % WORLD_WIDTH * BLOCK_SIZE; + player.ppy = player.py = i / WORLD_WIDTH * BLOCK_SIZE; + player.vx = 0; + player.vy = 0; + player.ax = 0; + player.ay = GRAVITY; + player.w = player.h = BLOCK_SIZE; + player.m = player.w * player.h; + } + } </code></pre> -<p> -入力によって変更された速度は、<code>main()</code>関数内で次の座標を計算するために使用される: +<p>ユーザーからの入力を受けとり、プレイーヤの加速度等を変更。<code>A</code>、<code>D</code>でそれぞれ左右に加速し、地面に接しているときに<code>space</code>キーでジャンプさせる: </p> -<pre><code>float px = 200, py = 200; -float vx = 0, vy = 0; -int width = 40, height = 40; +<pre><code>void +handle_inputs(int key_state[]) +{ + if (key_state[KEY_Q] == KEY_DOWN){ + next_menu = GAME_OVER; + return; + } + if (key_state[KEY_D] == KEY_DOWN) { + if (player.vx > 0) { + player.ax = 500; + } else { + player.ax = 1000; + } + } else if (key_state[KEY_A] == KEY_DOWN) { + if (player.vx > 0) { + player.ax = -1000; + } else { + player.ax = -500; + } + } else { + if (player_is_falling) + player.ax = -player.vx; + else + player.ax = -3 * player.vx; + } -int -main(void) + if (player.vx < -200) player.vx = -200; + if (player.vx > 200) player.vx = 200; + if (!player_is_falling && key_state[KEY_SPACE] == KEY_DOWN) + player.vy = -450; +} +</code></pre> + +<p>変更した加速度は<code>rect_next_tick()</code>関数で次の位置を計算するのに使用。また画面の下に落ちた時にゲームオーバーになるように設定:</p> +<pre><code>void +rect_next_tick(struct rect *s, long ndt) // nano second { - /* ... */ - quit = 0; - while (!quit) { - handle_input() - /* ... */ - px = px + vx * dt / 1000 / 1000 / 1000; - py = py + vy * dt / 1000 / 1000 / 1000; - // bind within the window - if (px < 0) - px = 0; - if (win_width < px + width) - px = win_width - width; - if (py < 0) - py = 0; - if (win_height < py + height) - py = win_height - height; + s->ppx = s->px; + s->ppy = s->py; + s->vx += s->ax * ndt / 1000 / 1000 / 1000; + s->vy += s->ay * ndt / 1000 / 1000 / 1000; + s->px += s->vx * ndt / 1000 / 1000 / 1000; + s->py += s->vy * ndt / 1000 / 1000 / 1000; - XClearArea(display, window, - 0, 0, // position - win_width, win_height, // width and height - False); - XFillRectangle(display, window, gc, - px, py, // position - width, height); // width and height + // bind within the window + if (s->px < 0) { + s->px = 0; + //s->vx *= -1; } - /* ... */ + if (win_width < s->px + s->w) { + s->px = win_width - s->w; + //s->vx *= -1; + } + // game over when fall out of the screen + if (s->py > win_height) + next_menu = GAME_OVER; } </code></pre> + <h2>完成品</h2> -<a href="https://git.mtkn.jp/xlib_playground/file/ex2/ex2.c.html">ソースコード</a> -<p>色を変えてみた。</p> +<p> +<a href="https://git.mtkn.jp/xlib_playground/file/ex6/ex6.c.html">git</a> +</p> +<p> <video controls> - <source src="videos/ex2.webm" type="video/webm"> +<source src="videos/ex6.webm" type="video/webm"> </video> +</p> <h2>参考</h2> <ul> <li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> </ul> -<p>次の記事: <a href="xlib_playground3.html">Xlibで遊んでみる3</a> -</p> ]]></description> </item> <item> -<title>Xlibで遊んでみる1</title> -<link>https://www.mtkn.jp/computer/xlib_playground1.html</link> -<guid>https://www.mtkn.jp/computer/xlib_playground1.html</guid> +<title>Xlibで遊んでみる5</title> +<link>https://www.mtkn.jp/computer/xlib_playground5.html</link> +<guid>https://www.mtkn.jp/computer/xlib_playground5.html</guid> <pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> -<description><![CDATA[<h1>Xlibで遊んでみる1</h1> -<time>2022-12-21</time> +<description><![CDATA[<h1>Xlibで遊んでみる5</h1> +<time>2023-01-03</time> -<h2>はじめに</h2> -<p>X11でGUIのプログラミングをしてみようと思い、してみた。X11用の低レベルのライブラリはXlibとxcbの二つがあるようだ。x.orgのウェブページを見てみると、Xlibは古く、xcbに置きかわりつつあるという。そのため、新しくなにかを作る場合はxcbを使うようにとのことである。ところがこのxcbはドキュメンテーションに乏しく、X11を触るのが初めての人間にはなにをどうすればいいのかほとんど分からなかった。知らない関数や構造体やらがでてきても(殆ど全部知らないものだが)、その関数なり構造体なりの説明がどこにも見当たらない。manページもない。あるのはdoxygenなるものでソースコードのコメントから自動生成したいい加減なものだけで、使いものにならない。</p> -<p>とりあえずX11のことを少しは理解してからでないと初められそうもないと思い、もう少しましな情報があるXlibから始めることにした。</p> -<p>言語はC言語である。ソースコードは<a href="https://git.mtkn.jp/xlib_playground">ここ</a>にある。 +<p> +前回: <a href="xlib_playground4.html">Xlibで遊んでみる4</a> +</p> +<p> +言語: C言語<br /> +ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> </p> -<h2>初期設定</h2> -<p>ディスプレイを開き、ウィンドウを作成する。変数はとりあえずグローバルに宣言することにした。<code>main</code>関数はできるだけ小さくして実際の処理はそれぞれの関数にさせてみる:</p> -<pre><code> -#include &lt;stdio.h&gt; -#include &lt;stdlib.h&gt; -#include &lt;X11/Xlib.h&gt; - -/* macros */ -#define INIT_WIDTH 800 -#define INIT_HEIGHT 600 - -/* variables */ -Display *display; -Window window; -unsigned int win_width = INIT_WIDTH, win_height = INIT_HEIGHT; -GC gc; -Atom wm_delete_window; +<h2>円の衝突判定とその処理</h2> +<p> +前回四角形で行っていた衝突判定とその処理を今回は円でした。衝突の判定は二つの円の中心間の距離と、各円の半径の和を比較するだけなので簡単である: +</p> +<pre><code>struct circle { + float ppx, ppy; // previous position (center) + float px, py; // current position (center) + float vx, vy; // velocity + int r; // radius + int m; // mass +}; -void -setup(void) +int +circle_test_collision(struct circle *c1, struct circle *c2) { - // Open a display. - if ((display = XOpenDisplay(NULL)) == NULL){ - fprintf(stderr, "ERROR: could not open display\n"); - exit(1); - } - // Create a window. - window = XCreateSimpleWindow( - display, - XDefaultRootWindow(display), - 0, 0, - win_width, win_height, - 0, 0, // border properties - 0); // background color: black - XStoreName(display, window, "UNKO"); - - // Setup a graphical context. - gc = XCreateGC(display, window, 0, NULL); - XSetForeground(display, gc, 0x0000FF); - - // Kill the application when the window is destroyed. - wm_delete_window = XInternAtom(display, - "WM_DELETE_WINDOW", False); - XSetWMProtocols(display, window, &wm_delete_window, 1); - - // Setup which input to process. - XSelectInput(display, window, - ExposureMask|KeyPressMask|KeyReleaseMask); - - // Actually draw the window. - XMapWindow(display, window); + return (c1->px - c2->px) * (c1->px - c2->px) + + (c1->py - c2->py) * (c1->py - c2->py) < + (c1->r + c2->r) * (c1->r + c2->r); } +</code></pre> +<p> +衝突後は前回と同じく弾性衝突として処理した。四角形とは違い、衝突方向の場合分けが不要なので楽である。 +</p> +<pre><code> void -clean_up(void) +circle_handle_collision_mm(struct circle *c1, struct circle *c2) { - XCloseDisplay(display); -} -</code></pre> + if (!circle_test_collision(c1, c2)) + return; -<p>適当な四角形のものを表示し、その位置を時間の関数として動かしてみる。</p> -<pre><code>#include &lt;time.h&gt; -#include &lt;math.h&gt; + float col_px = c2->px - c1->px; + float col_py = c2->py - c1->py; + float col_pr = sqrtf(col_px * col_px + col_py * col_py); + col_px /= col_pr; + col_py /= col_pr; + + c1->px = c1->px - col_px / 2; + c1->py = c1->py - col_py / 2; + c2->px = c2->px + col_px / 2; + c2->py = c2->py + col_py / 2; +} -int -main(void) +void +circle_handle_collision_elastic(struct circle *c1, struct circle *c2) { - int px, py; - int quit; - struct timespec ts; - XEvent event; + if(!circle_test_collision(c1, c2)) + return; - setup(); - quit = 0; + float col_px = c2->px - c1->px; + float col_py = c2->py - c1->py; + float col_pr = sqrtf(col_px * col_px + col_py * col_py); + col_px /= col_pr; + col_py /= col_pr; + float nor_px = col_py; + float nor_py = -col_px; - while (!quit){ - while(XPending(display) > 0){ - XNextEvent(display, &event); - switch (event.type){ - case KeyPress: { - switch (XLookupKeysym(&event.xkey, 0)){ - case 'q': - quit = 1; - break; - default: - break; - } - } break; - case ClientMessage: { - if ((Atom) event.xclient.data.l[0] == wm_delete_window) { - quit = 1; - } - } break; - default: - break; - } - } - clock_gettime(CLOCK_MONOTONIC, &ts); - px = 200 + (int) (100 * sinf(ts.tv_sec + ts.tv_nsec / 1000.0 / 1000 / 1000)); - py = 200 + (int) (100 * cosf(ts.tv_sec + ts.tv_nsec / 1000.0 / 1000 / 1000)); - XClearArea(display, window, - 0, 0, // position - win_width, win_height, // width and height - False); - XFillRectangle(display, window, gc, - px, py, // position - 100, 100); // width and height + float m1 = c1->m; + float m2 = c2->m; - ts.tv_sec = 0; - ts.tv_nsec = 10 * 1000 * 1000; - nanosleep(&ts, NULL); - } + float col_1v = c1->vx * col_px + c1->vy * col_py; + float col_2v = c2->vx * col_px + c2->vy * col_py; - cleanup(); - return 0; + float col_1vxn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_px; + float col_1vyn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_py; + float col_2vxn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_px; + float col_2vyn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_py; + + float nor_1vx = nor_px * (c1->vx * nor_px + c1->vy * nor_py); + float nor_1vy = nor_py * (c1->vx * nor_px + c1->vy * nor_py); + float nor_2vx = nor_px * (c2->vx * nor_px + c2->vy * nor_py); + float nor_2vy = nor_py * (c2->vx * nor_px + c2->vy * nor_py); + + c1->vx = col_1vxn + nor_1vx; + c1->vy = col_1vyn + nor_1vy; + c2->vx = col_2vxn + nor_2vx; + c2->vy = col_2vyn + nor_2vy; + + circle_handle_collision_mm(c1, c2); } </code></pre> -<p>ここまでのコードはgitリポジトリの<a href="https://git.mtkn.jp/xlib_playground/file/ex1/ex1.c.html">ex1/ex1.c</a>にある。</p> -<h2>完成品:</h2> +<h2>完成品</h2> +<p> +<a href="https://git.mtkn.jp/xlib_playground/file/ex5/ex5.c.html">git</a> +</p> +<p> <video controls> - <source src="videos/ex1.webm" type="video/webm"> +<source src="videos/ex5.webm" type="video/webm"> </video> +</p> <h2>参考</h2> <ul> <li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> -<li><a href="https://www.youtube.com/watch?v=764fnfEb1_c">X11 App in C with Xlib(youtube video by tsoding)</a></li> </ul> - -<a href="xlib_playground2.html">次の記事</a> +<p> +次の記事: <a href="xlib_playground6.html">Xlibで遊んでみる6</a> +</p> ]]></description> </item> <item> -<title>RP2040 SDKなしでLチカ</title> -<link>https://www.mtkn.jp/computer/rp2040_1.html</link> -<guid>https://www.mtkn.jp/computer/rp2040_1.html</guid> +<title>Xlibで遊んでみる4</title> +<link>https://www.mtkn.jp/computer/xlib_playground4.html</link> +<guid>https://www.mtkn.jp/computer/xlib_playground4.html</guid> <pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> -<description><![CDATA[<h1>RP2040 SDKなしでLチカ</h1> -<time>2023-04-25</time> +<description><![CDATA[<h1>Xlibで遊んでみる4</h1> +<time>2023-01-02</time> -<h2>はじめに</h2> -<p> -パタヘネのRISC-V<sup>[1]</sup>版を買って一通り読んだらアセンブリ言語で組込のプログラミングがしたくなった。RISC-Vのマイコンボードが欲しかったのだが、安くていい感じのものが見付からなかった。代わりに秋月電子通商でArmのものがあった。RP2040マイコンボードキット<sup>[2]</sup>というものである。ウェブ上の情報も多く、データシート<sup>[3]</sup>もしっかりしていそうなので、とりあえずこれを買ってみた。</p> <p> -一般的にはSDK<sup>[4]</sup>をダウンロードしてあらかじめ用意されたライブラリを使って開発するようだが、これはビルドシステムとしてcmakeというのを使っている。これがOpenBSDでは何かエラーがでて動かなかった。僕はこういう便利ツールが嫌いだ。どうせ使わんからいいんやけど。関係ないけど途中から開発環境がLinuxに替わった。SDKには便利な関数がたくさん用意されているので楽である。ハードウェアの面倒な部分がプログラマから見えないようにしているからである。しかし今回はその面倒な部分に触れてみたくて買ったので、SDKを使うと意味がない。</p> -<p> -ということでSDKなしで開発してみる。とりあえず定番のLチカをば。</p> +前回: <a href="xlib_playground3.html">Xlibで遊んでみる3</a> +</p> <p> -ソースコード: <a href="https://git.mtkn.jp/rp2040">git</a> +言語: C言語<br /> +ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> </p> -<h2>動作環境</h2> -<ul> -<li>Arch Linux 6.2.12-arch1-1 - <ul> - <li>arm-none-eabi-binutils 2.40-1</li> - <li>GNU Make 4.4.1</li> - </ul> -</li> -<li>OpenBSD 7.3 - <ul> - <li>arm-none-eabi-binutils 2.31.1</li> - <li>make (バージョン?)</li> - </ul> -※<code>make flash</code>は動かん。<code>dmesg</code>でデバイス確認して手動でマウントする必要がある。 -</li> -</ul> - -<h2>Boot Process</h2> +<h2>衝突判定とその処理</h2> <p> -RP2040は電源を入れるといくつかの段階(ここでは関係ないので省略。データシート「2.8.1 Processor Controlled Boot Sequence」に詳しく書いてある)を踏んだあと、外部のフラッシュROMの先頭から256バイトを内部のSRAMにコピーして、フラッシュにプログラムが書き込まれているかどうか確認する。RP2040はフラッシュの先頭252バイトから計算したCRC32チェックサムを、直後の253バイト目から256バイトに記録することになっている。起動時にこのチェックサムを確認することで、フラッシュにプログラムが書き込まれているかどうか確かめている。コピーした最後の4バイトと起動時に最初の252バイトから計算したチェックサムが一致していれば、そのままコピーしてきた256バイトの先頭にPCをセットして実行を開始する。一致しなければUSBデバイスモードに切り替わり、パソコンに接続するとストレージとして認識される。このストレージにUF2という形式に変換したプログラムをコピーするとプログラムがフラッシュROMやSRAMに書き込まれる。 -</p> +これまでは一つの四角形だけを描画していたが、今回は複数の四角形を作成して動かしてみた。ランダムな場所にランダムな運動量で動かして、他のものやウィンドウの縁とぶつかったら跳ね返るようにした。</p> <p> -以上のことから、プログラムを実行するためにはCRC32を計算し、UF2という形式に変換することが必要である。ソースコードからの流れは以下の通り: +回転しない四角形どうしの衝突判定は簡単である。x軸方向とy軸方向の両方に重なりがあれば衝突している: </p> -<pre>source bin bin with -code ----------> object ------> elf --------> bin -------> with --------> crc32 in - crc32 uf2 format - assemble link objcopy bincrc bin2uf2 -</pre> +<pre><code>struct square { + float ppx, ppy; // previous position + float px, py; // current position + float vx, vy; // velocity + int w, h; // width and height +}; + +int +test_collision(struct square *s1, struct square* s2) +{ + return s1->px < s2->px + s2->w && s2->px < s1->px + s1->w && + s2->py < s1->py + s1->h && s1->py < s2->py + s2->h; +} +</code></pre> -<h2>CRC(巡回冗長検査)</h2> -<p> -入力のデータをごにょごにょしてある値を出力する。<blockquote cite="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB"> <p> -データ転送等に伴う偶発的な誤りの検査によく使われている<sup>[5]</sup>。 -</p> -</blockquote> -らしい。 +衝突後の処理は多少めんどくさかった。衝突した時は既にめりこんでいるので、まずはそれぞれをめりこんだ距離の半分ずつずらして衝突を解消するようにした。この際、x軸方向にぶつかったのか、y軸方向にぶつかったのかで、それぞれの軸方向にひっぺがすようにしている。二つの四角形の各軸に関するめりこんだ距離<code>lapx</code>、<code>lapy</code>と各軸に関する相対速度<code>rel_vx</code>、<code>rel_vy</code>の比を比べればどちらの軸方向にぶつかったかが分かるはずである、多分 : </p> +<pre><code>void +handle_collision_mm(struct square *s1, struct square *s2) +{ + if (!test_collision(s1, s2)) + return; + + float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px); + float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py); + float rel_vx = max(s1->vx - s2->vx, s2->vx - s1->vx); + float rel_vy = max(s1->vy - s2->vy, s2->vy - s1->vy); + + if (lapx / rel_vx < lapy / rel_vy) { + if (s1->px + s1->w < s2->px + s2->w / 2) { + s1->px -= lapx / 2; + s2->px += lapx / 2; + } else { + s1->px += lapx / 2; + s2->px -= lapx / 2; + } + } else { + if (s1->py + s1->h < s2->py + s2->h / 2) { + s1->py -= lapy / 2; + s2->py += lapy / 2; + } else { + s1->py += lapy / 2; + s2->py -= lapy / 2; + } + } +} +</pre></code> <p> -入力のビットを一列に並べて、除数で「割り算」していく。この「割り算」が多項式の除算に似ているので、この除数をCRC多項式というらしい。ただし多項式の除算と違い、引き算するところをXORする。CRC32の場合、除数は33ビットである。33ビットで割ると32ビットの余りが残る。この余りがCRC32のチェックサムである。除数は色々あるようだが、標準的なものがWikipedia<sup>[5]</sup>に列挙されている。除数<code>1011</code>を使ったCRC3の計算の手順は以下の通り: +衝突は弾性衝突として、衝突したそれぞれの四角形の速度を更新した。質量は四角形の面積として計算している。衝突後の速度はエネルギー保存則と運動量保存則から導いたのでしんどかった。 </p> -<pre><code>1110101011011100110101101101111 入力(適当) -1011 除数(4ビット) -------------------------------- - 101101011011100110101101101111 結果(入力と除数のXOR) - 1011 - ------------------------------ - 00001011011100110101101101111 - 1011 - ------------------------- - 000011100110101101101111 - 1011 - -------------------- - 1010110101101101111 - 1011 - ------------------- - 001110101101101111 - 1011 - ---------------- - 101101101101111 - 1011 - --------------- - 00001101101111 - 1011 - ---------- - 110101111 - 1011 - --------- - 11001111 - 1011 - -------- - 1111111 - 1011 - ------- - 100111 - 1011 - ------ - 01011 - 1011 - ---- - 000 CRC3チェックサム +<pre><code>void +handle_collision_elastic(struct square *s1, struct square *s2) +{ + if(!test_collision(s1, s2)) + return; + + float v1, v2; + float m1 = s1->w * s1->h; + float m2 = s2->w * s2->h; + + float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px); + float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py); + + if (lapx < lapy) { + v1 = s1->vx; + v2 = s2->vx; + s1->vx = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1; + s2->vx = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2; + } else { + v1 = s1->vy; + v2 = s2->vy; + s1->vy = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1; + s2->vy = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2; + } + + handle_collision_mm(s1, s2); +} </code></pre> + +<h2>サブティック</h2> <p> -普通の割り算と基本は同じであるが、引き算の部分だけXORになっている。</p> -<p> -以上の計算をプログラムの先頭252バイトに対して、33ビットの除数を用いて行う。データの並べ方は、上の例において左側を先頭に、フラッシュROM上の0番地から、各バイトは最上位ビットから順に並べる。入力のデータは253バイト目から256バイト目に<code>0</code>をひっつけて計算する。これは多分予め長さが分からないデータでも計算できるようにしたかったからかな。除数は<code>0x104c11db7</code>である(最上位ビットは常に1なのでデータシートでは省略されている)。</p> -<p> -入力データは1バイトづつ処理したいみたいである。多分通信等で使う都合である。この時XORは結合則が成り立つので1バイト処理した結果と次のバイトとをXORして次の処理の入力として利用することができる: +この名前が適切かどうか分からないが、前のフレームから次のフレームまでの時間をさらに何等分かして衝突判定の制度を上げた(マクロは括弧でかこって分かりにくいバグを防げとどこかに書いていたのでそうすることにした): </p> -<pre><code>111000111000000110000110111000111000001010010011111000111000000110010011 入力(適当) -|......| -111000110000000000000000000000000 先頭1バイト -100000100110000010001110110110111 除数 ------------------------------------------------------------------------- -011000010110000010001110110110111 - 100000100110000010001110110110111 - ----------------------------------------------------------------------- - 010000001010000110010011011011001 - 100000100110000010001110110110111 - ---------------------------------------------------------------------- - 000000110010001110101000000000101 -|......| - 110010001110101000000000101000000 1バイト目の結果 - |......| - 10000001 入力の2バイト目 - ---------------------------------------------------------------- - 010010011110101000000000101000000 1バイト目の結果と2バイト目のXOR - 100000100110000010001110110110111 除数 - ---------------------------------------------------------------- - 000100011011010010001111100110111 - . - . - . +<pre><code>#define SUB_TIC (4) + +void +game_play(void) +{ + /* ... */ + while (next_menu == GAME_PLAY) { + /* ... */ + for (int j = 0; j < SUB_TICK; j++) { + for (int i = 0; i < NUM_SQUARE; i++) + next_tick(&square[i], 1000 * 1000 * 1000 / FPS / SUB_TICK); + + for (int i = 0; i < NUM_SQUARE; i++) + for (int j = i + 1; j < NUM_SQUARE; j++) { + handle_collision_elastic(&square[i], &square[j]); + /* ... */ + } + /* ... */ + } + /* ... */ + } + /* ... */ +} </code></pre> + +<h2>完成品</h2> <p> -以上の操作は以下のようなアルゴリズムのループで実装できる。</p> +<a href="https://git.mtkn.jp/xlib_playground/file/ex4/ex4.c.html">git</a> +</p> +<p> +<video controls> +<source src="videos/ex4.webm" type="video/webm"> +</video> +</p> + +<h2>参考</h2> <ul> -<li>前回の結果と、入力データの次のバイトをXOR</li> -<li> - <ul> - <li>先頭の1ビットが1の場合、除数とXORを取り左シフト</li> - <li>先頭の1ビットが0の場合、そのまま左シフト</li> - </ul> -</li> +<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> </ul> <p> -これを<code>for</code>ループで回す都合上、最初のバイトもXORを取る。上の例では最初は<code>0x0</code>とXORを取っているが、この値を<code>0x0</code>以外にすることもできる。そうした方がいろいろいいこともあるらしい。RP2040では<code>0xffffffff</code>を使う。更にこの工程を32ビットの<code>int</code>だけで行うことを考える: +次の記事: <a href="xlib_playground5.html">Xlibで遊んでみる5</a> </p> -<pre><code>111000111000000110000110111000111000001010010011111000111000000110010011 入力(適当) +]]></description> +</item> +<item> +<title>Xlibで遊んでみる3</title> +<link>https://www.mtkn.jp/computer/xlib_playground3.html</link> +<guid>https://www.mtkn.jp/computer/xlib_playground3.html</guid> +<pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> +<description><![CDATA[<h1>Xlibで遊んでみる3</h1> +<time>2023-01-02</time> -11111111111111111111111111111111 0xffffffff -11100011000000000000000000000000 先頭1バイトを24ビットシフト --------------------------------- XOR -00011100111111111111111111111111 -先頭1ビットが0なので1ビットシフト --------------------------------- シフト -00111001111111111111111111111110 -先頭1ビットが0なので1ビットシフト --------------------------------- シフト -01110011111111111111111111111100 -先頭1ビットが0なので1ビットシフト --------------------------------- シフト -11100111111111111111111111111000 -先頭1ビットが1なので1ビットシフトした後、除数の下位32ビットとXOR: -11001111111111111111111111110000 シフト -00000100110000010001110110110111 除数の下位32ビット --------------------------------- XOR -11001011001111101110001001000111 -先頭1ビットが1なので1ビットシフトした後、除数の下位32ビットとXOR: -10010110011111011100010010001110 シフト -00000100110000010001110110110111 除数の下位32ビット --------------------------------- XOR -10010010101111001101100100111001 -先頭1ビットが1なので1ビットシフトした後、除数の下位32ビットとXOR: -00100101011110011011001001110010 シフト -00000100110000010001110110110111 除数の下位32ビット --------------------------------- XOR -00100001101110001010111111000101 -先頭1ビットが0なので1ビットシフト --------------------------------- シフト -01000011011100010101111110001010 -先頭1ビットが0なので1ビットシフト --------------------------------- シフト -10000110111000101011111100010100 1バイト目の結果 +<p> +前回: <a href="xlib_playground2.html">Xlibで遊んでみる2</a> +</p> +<p> +言語: C言語<br /> +ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> +</p> -10000001 入力の2バイト目 --------------------------------- XOR -00000111111000101011111100010100 -先頭1ビットが0なので1ビットシフト --------------------------------- シフト -00001111110001010111111000101000 -. -. -. +<h2>画面サイズの変更</h2> +<p> +画面サイズが変更された時に表示している四角形が画面の外側に出ないようにした。<code>XGetWindowAttributes()</code>で画面の情報を取得し、グローバル変数の<code>win_width</code>と<code>win_height</code>に幅と高さをそれぞれ代入して<code>next_tick()</code>で四角形の位置を画面に収まるようにしている: +</p> +<pre><code>int win_width, win_height; + +void +receive_events(int key_state[]) +{ + XEvent event; + XWindowAttributes wattr; + + while (XPending(display) > 0) { + XNextEvent(display, &event); + switch (event.type) { + case Expose: { + XGetWindowAttributes(display, window, &wattr); + win_width = wattr.width; + win_height = wattr.height; + } break; + /* ... */ + } + } +} + +void +next_tick(long ndt) // nano second +{ + px = px + vx * ndt / 1000 / 1000 / 1000; + py = py + vy * ndt / 1000 / 1000 / 1000; + // bind within the window + if (px < 0) + px = 0; + if (win_width < px + width) + px = win_width - width; + if (py < 0) + py = 0; + if (win_height < py + height) + py = win_height - height; +} </code></pre> + +<h2>メニュー画面の実装</h2> <p> -これを実装したのが以下のコード:</p> -<pre><code>uint32_t -crc32(uint8_t *idata, size_t len) +ゲームのようなものを作るうえでメニュー画面とその推移が必要である。ここではグローバル変数<code>next_menu</code>に現在のメニューを保存することにした。それぞれのメニューはそれぞれ関数として記述し、他のメニューに推移する必要が生じたときに<code>next_menu</code>を変更するようにした: +</p> +<pre><code>enum next_menu { + START_MENU, + GAME_PLAY, + GAME_OVER, + QUIT, +}; + +int next_menu = START_MENU; + +void +start_menu(void) { - uint32_t pol = 0x04C11DB7; - uint32_t c = 0xFFFFFFFF; - uint32_t b; + XEvent event; + char *menu_char_q = "press q to quit."; + char *menu_char_s = "press <space> to start."; + + XClearArea(display, window, + 0, 0, // position + win_width, win_height, // width and height + False); + XDrawString(display, window, gc, + win_width/2 - strlen(menu_char_q)/2, win_height/2, + menu_char_q, strlen(menu_char_q)); + XDrawString(display, window, gc, + win_width/2 - strlen(menu_char_s)/2, win_height/2 + 20, + menu_char_s, strlen(menu_char_s)); + + while (next_menu == START_MENU) { + XNextEvent(display, &event); + switch (event.type) { + case Expose: { + XDrawString(display, window, gc, + win_width/2 - strlen(menu_char_q)/2, + win_height/2, + menu_char_q, strlen(menu_char_q)); + XDrawString(display, window, gc, + win_width/2 - strlen(menu_char_s)/2, + win_height/2 + 20, + menu_char_s, strlen(menu_char_s)); + + } break; + case KeyPress: { + switch (XLookupKeysym(&event.xkey, 0)) { + case 'q': + next_menu = QUIT; + break; + case ' ': + next_menu = GAME_PLAY; + break; + default: + break; + } + } break; + case ClientMessage: { + if ((Atom) event.xclient.data.l[0] == wm_delete_window) { + next_menu = QUIT; + } + } break; + default: + break; + } + } +} - for (int i = 0; i &lt; len; i++) { - b = idata[i] &lt;&lt; 24; - c ^= b; - for (int j = 0; j &lt; 8; j++) { - c = c &gt;&gt; 31 & 1 ? c &lt;&lt; 1 ^ pol : c &lt;&lt; 1; +int +main(void) +{ + setup(); + while (next_menu != QUIT){ + switch (next_menu){ + case START_MENU: + start_menu(); + break; + case GAME_PLAY: + game_play(); + break; + case GAME_OVER: + game_over(); + break; + default: + break; } } - return c; + cleanup(); + return 0; } </code></pre> -<p> -<code>main()</code>関数では上の<code>crc32()</code>に、<code>idata</code>として入力となるバイナリデータの先頭を、<code>len</code>として<code>252</code>を渡してCRC32を計算させる。その後、出力先のファイルに入力元のデータをコピーしていき、253バイト目から256バイト目だけ、計算したCRC32に置き換える。入力元のこの場所にデータが書き込まれていないかどうかは確かめていない。 -</p> +<p><code>main()</code>関数がめっちゃすっきりした。</p> -<h2>UF2(USB Flashing Format)</h2> -<p> -Microsoftが開発したフラッシュ書き込み用のファイル形式らしい: -<blockquote cite="https://github.com/microsoft/uf2"> +<h2>完成品</h2> <p> -UF2 is a file format, developed by Microsoft for PXT (also known as -Microsoft MakeCode), that is particularly suitable for flashing microcontrollers -over MSC (Mass Storage Class; aka removable flash drive)<sup>[6]</sup>. +<a href="https://git.mtkn.jp/xlib_playground/file/ex3/ex3.c.html">git</a> </p> -</blockquote> <p> -このファイルに変換する上で必要な情報はGitHubのmicrosoft/uf2<sup>[6]</sup>に表として纏められている: -<blockquote cite"https://github.com/microsoft/uf2"> -<table> -<thead><tr> -<th>Offset</th><th>Size</th><th>Value</th> -</tr></thead> -<tbody> -<tr> -<td>0</td> -<td>4</td> -<td>First magic number, <code>0x0A324655</code> (<code>"UF2\n"</code>)</td> -</tr> -<tr> -<td>4</td> -<td>4</td> -<td>Second magic number, <code>0x9E5D5157</code></td> -</tr> -<tr> -<td>8</td> -<td>4</td> -<td>Flags</td> -</tr> -<tr> -<td>12</td> -<td>4</td> -<td>Address in flash where the data should be written</td> -</tr> -<tr> -<td>16</td> -<td>4</td> -<td>Number of bytes used in data (often 256)</td> -</tr> -<tr> -<td>20</td> -<td>4</td> -<td>Sequential block number; starts at 0</td> -</tr> -<tr> -<td>24</td> -<td>4</td> -<td>Total number of blocks in file</td> -</tr> -<tr> -<td>28</td> -<td>4</td> -<td>File size or board family ID or zero</td> -</tr> -<tr> -<td>32</td> -<td>476</td> -<td>Data, padded with zeros</td> -</tr> -<tr> -<td>508</td> -<td>4</td> -<td>Final magic number, <code>0x0AB16F30</code></td> -</tr> -</tbody> -</table> -</blockquote> +<video controls> +<source src="videos/ex3.webm" type="video/webm"> +</video> +</p> +<h2>参考</h2> +<ul> +<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> +</ul> <p> -RP2040のデータシート<sup>[3]</sup>「2.8.4.2 UF2 Format Details」を見ると、8バイト目のFlagsは、28バイト目にファミリーIDが書き込まれていることを示す<code>0x00002000</code>、12バイト目は、書き込みを行うフラッシュROMの先頭アドレスである<code>0x10000000</code>に、各ブロックの先頭からの位置を足したもの、16バイト目の、各ブロックのデータサイズは256バイト、28バイト目のファミリーIDは<code>0xe48bff56</code>である。あとは表の通り3つのマジックナンバーをセットし、32バイト目以降にデータを書き込み、20バイト目と24バイト目にブロックの通し番号と総数をそれぞれ書き込めばいい。ブロックの通し番号はデータのついでに書き込めるが、総数はデータを全部さばいた後でないと分からないので、最後全てのブロックにまとめて書き込むようにした。できたのが以下のコード: +次の記事: <a href="xlib_playground4.html">Xlibで遊んでみる4</a> </p> -<pre><code>#include &lt;stdio.h&gt; -#include &lt;stdint.h&gt; -#include &lt;stdlib.h&gt; -#include &lt;string.h&gt; +]]></description> +</item> +<item> +<title>Xlibで遊んでみる2</title> +<link>https://www.mtkn.jp/computer/xlib_playground2.html</link> +<guid>https://www.mtkn.jp/computer/xlib_playground2.html</guid> +<pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> +<description><![CDATA[<h1>Xlibで遊んでみる2</h1> +<time>2022-12-22</time> +<p>前回: <a href="xlib_playground1.html">Xlibで遊んでみる1</a></p> +<p>言語はC言語である。ソースコードは<a href="https://git.mtkn.jp/xlib_playground">ここ</a>にある。 +</p> -size_t -fwrite32l(uint32_t d, FILE *f) -{ - int i; - uint8_t b; - for (i = 0; i &lt; 32; i += 8) { - b = (uint8_t) (d &gt;&gt; i & 0xff); - fwrite(&amp;b, 1, 1, f); - if (ferror(f)) { - fprintf(stderr, "Fwrite32l: write error.\n"); - return 0; - } - } - return 4; -} +<h2>FPSの固定</h2> +<p>前のフレームからの経過時間を計測して<code>1.0/FPS</code>を越えるまで待機させる。このときに<code>nanosleep()</code>を使うとなぜか上手くいかなかった。ナノ秒単位で処理できそうな名前なのに使えない。多分OSのコンテクストスイッチがどうとかいう話やと思う。知らんけど。組み込みとかで使うんかな? +</p> + +<p> +とりあえず<code>while</code>ループの中でひたすら時刻を読んでいる。リソースの無駄遣いではないのだろうか: +</p> +<pre><code>#defin FPS 60 int -main(int argc, char *argv[]) +main(void) { - FILE *src = NULL, *dst = NULL; - size_t sdata = 476; - int retnum = 0; - - uint32_t mag1 = 0x0A324655; - uint32_t mag2 = 0x9E5D5157; - uint32_t flags = 0x00002000; // familyID present - uint32_t addr = 0x10000000; - uint32_t nbyte = 256; - uint32_t blk = 0; - uint32_t nblk = 0; - uint32_t famid = 0xe48bff56; - uint8_t data[sdata]; - uint32_t mag3 = 0x0AB16F30; - - memset(data, 0, sdata); - - if (argc != 3) { - fprintf(stderr, "Usage: %s src dst\n", argv[0]); - exit(1); - } + long t0, t1, dt; + int fps_count; - if ((src = fopen(argv[1], "rb")) == NULL) { - fprintf(stderr, "Could not open %s.\n", argv[1]); - retnum = 1; - goto defer; - } - if ((dst = fopen(argv[2], "wb")) == NULL) { - fprintf(stderr, "Could not open %s.\n", argv[2]); - retnum = 1; - goto defer; - } - - while (!feof(src)) { - fwrite32l(mag1, dst); - fwrite32l(mag2, dst); - fwrite32l(flags, dst); - fwrite32l(addr, dst); - fwrite32l(nbyte, dst); - fwrite32l(blk, dst); - fwrite32l(nblk, dst); // dummy - fwrite32l(famid, dst); + clock_gettime(CLOCK_MONOTONIC, &ts); + t0 = ts.tv_nsec; - fread(data, 1, nbyte, src); - if (ferror(src)) { - fprintf(stderr, "Read error: %s.\n", argv[1]); - retnum = 1; - goto defer; + while (!quit) { + // fix fps + dt = 0; + while (dt < 1.0 * 1000 * 1000 * 1000 / FPS){ + clock_gettime(CLOCK_MONOTONIC, &ts); + t1 = ts.tv_nsec; + dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000; } - fwrite(data, 1, sdata, dst); - if (ferror(src)) { - fprintf(stderr, "Write error: %s.\n", argv[2]); - retnum = 1; - goto defer; + // count fps. + fps_count++; + if (t1 < t0){ + printf("fps: %u\n", fps_count); + fps_count = 0; } - - fwrite32l(mag3, dst); - - addr += nbyte; - blk++; - nblk++; - } - - for (int i = 0; i &lt; nblk; i++) { - if (i == 0) - if (fseek(dst, 24, SEEK_SET) &lt; 0) { - fprintf(stderr, "Seek error: %s.\n argv[2]"); - retnum = 1; - goto defer; - } - fwrite32l(nblk, dst); - if (i &lt; nblk - 1) - if(fseek(dst, 512 - 4, SEEK_CUR) &lt; 0){ - fprintf(stderr, "Seek error: %s.\n argv[2]"); - retnum = 1; - goto defer; - } - } - -defer: - if (src) - fclose(src); - if (dst) - fclose(dst); - return retnum; -} -</code></pre> -<p><code>fwrite32l()</code>関数は指定されたファイルに32ビットの整数を下位バイトから順に書き込む関数である。バイトオーダーとかややこしそうなので作っておいたけど必要なのかな?あと名前が気に入らない。</p> -<p> -CRC32のチェックサムが書き込まれたバイナリファイルを、このプログラムでUF2に変換し、生成されたファイルをUSBストレージとして接続したRP2040にコピーすればフラッシュROMに書き込まれる。 -</p> - -<h2>Flash Second Stage</h2> + clock_gettime(CLOCK_MONOTONIC, &ts); + t0 = ts.tv_nsec; + } +} +</code></pre> <p> -RP2040に電源を投入し、CRC32のチェックが通った後、フラッシュROMからコピーされたプログラムの先頭から実行が開始される。このコピーされた部分で、その後の動作に必要な各種の設定を行うことになる。RP2040のデータシートには、フラッシュROMとSSIコントローラのXIPを設定するようにと書かれている。XIPはExecute in Placeの略で、フラッシュROMの内容をCPUから直接実行するものである。SSIはSynchronous Serial Interfaceの略で、周辺機器と情報のやりとりをする通信方式である。RP2040はチップに内蔵されたこのSSIコントローラを通して、外部のフラッシュROMと通信しているのだが、このコントローラを適切に設定すればフラッシュROMの内容がCPUから直接アクセスできる<code>0x10000000</code>番地以降にマップされる。これによりフラッシュROMから内部のSRAMにデータをコピーすることなく命令を実行できるので、速くて便利だという。 -</p> +時刻は<code>clock_gettime()</code>で測定して1秒未満の部分: <code>tv_nsec</code>だけを利用している。<code>tv_nsec</code>はナノ秒ナノで、10<sup>9</sup>を掛けている。<code>dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000</code>で前回の時刻と現在の時刻の少数部分を比較している。繰り上がりがあれば前回の時刻よりも現在の時刻の方が小さくなるので1秒足すことで調整している。</p> <p> -しかしこのSSIコントローラはSynopsysという会社のDW_apb_ssiというIPを使っているようで、データシートのSSIコントローラの章は多分Synopsysの人が書いている。その他の章はRaspberry Pi財団の書いたブリティッシュイングリッシュだが、この部分だけ多分ネイティブじゃない人の書いたいい加減な英語である。誤植も多い。何日かかけて理解しようとしたがよく分からん。不毛なので一旦諦めた。</p> +FPSの計測の部分は、フレーム毎に<code>fps_count</code>を1ずつ増やし、ナノ秒が繰り上がった時点での<code>fps_count</code>を表示している。</p> <p> -RP2040には内部にもROMがあり、はバージョン情報や電源を投入した時の動作、その他便利な関数が書き込まれている。この関数の中に外部のフラッシュROMとSSIコントローラを設定するものも含まれているので、今回はこれを利用した。ただしこの方法だとフラッシュROMとの通信方式がStandard SPIのままなので少し遅いらしい。詳しくはデータシートの「2.3.8. Bootrom Contents」を参照。 +あまり正確な方法ではないように思うが、コンパクトにまとまったのではないだろうか。</p> + +<h2>キーボード入力の処理</h2> +<p>キーボードからの入力を受け取る:</p> +<pre><code>XSelectInput(display, window, + ExposureMask|KeyPressMask|KeyReleaseMask); +</code></pre> +<p>ここではキーボードのキーを押した時と離した時に<code>XEvent</code>の通知を受け取るように設定した。 </p> <p> -RP2040の内蔵ROMの<code>0x00000018</code>番地に関数を検索するための関数がある。この関数に<code>0x00000014</code>番地の<code>rom_func_table</code>と、各関数に割り当てられた二文字の文字列を渡せば、欲しい関数へのポインタが返ってくる。なお、二文字の文字列はそれぞれASCIIコードで現し、二文字目を8ビットシフトしたものと1文字目のORを取ったものを渡すことになっている。今回欲しい関数はフラッシュROMをXIPに設定するもの(<code>_flash_enter_cmd_xip()</code>)なので、<code>'C', 'X'</code>を渡す。関数のポインタが返ってきて、それを呼び出せばフラッシュROMとSSIはXIPモードになる: -</p> -<pre><code>setup_xip: - ldr r3, rom_base +<code>XNextEvent()</code>からひとつずつ入力を受け取ると、複数のキーが同時に押された時にうまく処理できなかったので、押されているキーを配列に保存しておくことにした:</p> +<pre><code>enum Keys { + Key_D, + Key_S, + Key_A, + Key_W, + Key_Space, + Num_Key, //number of keys in this enum +}; +enum Key_State { + Key_Up, + Key_Down, +}; - ldrh r0, [r3, #0x14] // rom_func_table - ldr r1, =('C' | 'X' << 8) // _flash_enter_cmd_xip() - ldrh r2, [r3, #0x18] // rom_table_lookup - blx r2 - blx r0 -/* ... */ -rom_base: - .word 0x00000000 +int key_state[Num_Key]; </code></pre> <p> -XIPの設定が完了すれば、次はメインのプログラムを実行するための準備である。エントリーポイントの指定、スタックポインタの初期値の設定、ベクターテーブルの設定である。Armのマニュアル<sup>[7]</sup>によると、初期スタックポインタとエントリーポイントはベクターテーブルの<code>0x0</code>バイト目と<code>0x4</code>バイト目に書くことになっている: -<blockquote cite="https://developer.arm.com/documentation/ddi0419/c/System-Level-Architecture/System-Level-Programmers--Model/ARMv6-M-exception-model/Exception-number-definition"> -<table> -<caption> -Table 7.3. Exception numbers -</caption><colgroup><col><col></colgroup><thead><tr><th>Exception number</th><th>Exception</th></tr></thead><tbody><tr><td>1</td><td>Reset</td></tr><tr><td>2</td><td>NMI</td></tr><tr><td>3</td><td>HardFault</td></tr><tr><td>4-10</td><td>Reserved</td></tr><tr><td>11</td><td>SVCall</td></tr><tr><td>12-13</td><td>Reserved</td></tr><tr><td>14</td><td>PendSV</td></tr><tr><td>15</td><td>SysTick, optional</td></tr><tr><td>16</td><td>External Interrupt(0)</td></tr><tr><td>...</td><td>...</td></tr><tr><td>16 + N</td><td>External Interrupt(N)</td></tr></tbody> -</table> -</blockquote> - -<blockquote cite="https://developer.arm.com/documentation/ddi0419/c/System-Level-Architecture/System-Level-Programmers--Model/ARMv6-M-exception-model/The-vector-table"> -<table> -<caption> -Table 7.4. Vector table format -</caption><colgroup><col><col></colgroup><thead><tr><th>Word offset in table</th><th>Description, for all pointer address values</th></tr></thead><tbody><tr><td>0</td><td>SP_main. This is the reset value of the Main stack pointer.</td></tr><tr><td>Exception Number</td><td>Exception using that Exception Number</td></tr></tbody> -</table> -</blockquote> - -また、ベクターテーブルはメインのプログラムの先頭に置くことにする。メインのプログラムはFlash Second Stageが占有する256バイトの直後、フラッシュROMの257バイト目から配置することにする。RP2040のベクターテーブルはM0PLUS: VTOR(<code>0xe0000000 + 0xed08</code>)というレジスタに書き込むことで設定する。以上をまとめると以下のコードになる:</p> -<pre><code> ldr r0, flash_main - ldr r1, m0plus_vtor - str r0, [r1, #0] // vector table - ldr r1, [r0, #4] // entry point - ldr r0, [r0, #0] // stack pointer - mov sp, r0 - bx r1 +入力の処理は<code>handle_inputs()</code>関数内で行なう。<code>A</code>、<code>S</code>、<code>D</code>、<code>W</code>のうちどれかのキーが押されているとそれぞれ左、下、右、上方向に速度を加算するようにした。また、<code>Q</code>が押されるか、windowが破壊されると<code>quit</code>フラグを<code>1</code>にしてメインループから抜けるようにしている:</p> +<pre><code>int quit; -/* ... */ +void +handle_inputs(void) +{ + XEvent event; + while (XPending(display) > 0) { + XNextEvent(display, &event); + switch (event.type) { + case KeyPress: { + switch (XLookupKeysym(&event.xkey, 0)) { + case 'q': + quit = 1; + break; + case 'd': + key_state[Key_D] = Key_Down; + break; + case 'a': + key_state[Key_A] = Key_Down; + break; + case 'w': + key_state[Key_W] = Key_Down; + break; + case 's': + key_state[Key_S] = Key_Down; + break; + default: + break; + } + } break; + case KeyRelease: { + switch (XLookupKeysym(&event.xkey, 0)) { + case 'd': + key_state[Key_D] = Key_Up; + break; + case 'a': + key_state[Key_A] = Key_Up; + break; + case 'w': + key_state[Key_W] = Key_Up; + break; -flash_main: - .word 0x10000000 + 0x100 -m0plus_vtor: - .word 0xe0000000 + 0xed08 -</code></pre> -<p>なお以上のコードは<code>.boot2</code>という名前のセクションにしてある。 -</p> + case 's': + key_state[Key_S] = Key_Up; + break; + default: + break; + } + } break; + case ClientMessage: { + if ((Atom) event.xclient.data.l[0] == wm_delete_window) { + quit = 1; + } + } break; + default: + break; + } + } -<h2>メインのコード(<code>main.s</code>)<h2> -<h3>ベクターテーブル</h3> -<p> -メインのコードの最初には上で説明したベクターテーブルを配置する。ここでは割り込みの処理は考えないので、初期スタックポインタとエントリーポイントだけである。初期スタックポインタはSRAMの最後?(<code>0x20040000</code>)、エントリーポイントはエントリーポイントのラベルを用いて設定した。</p> -<pre><code>vectors: - .word 0x20040000 // initial SP - .word (reset+1) + vx = vy = 0; + if (key_state[Key_D] == Key_Down) + vx += 300; + if (key_state[Key_A] == Key_Down) + vx += -300; + if (key_state[Key_S] == Key_Down) + vy += 300; + if (key_state[Key_W] == Key_Down) + vy += -300; +} </code></pre> -<p> -<code>reset</code>ラベルに<code>1</code>を足しているのはRP2040がThumbモードのみに対応しているからである。ArmのCPUはArmモードとThumbモードがあり、Armモードは32ビットの命令で高機能。Thumbモードは16ビットの命令(一部32ビット)でコンパクトである。どちらのモードでも命令は2の倍数のアドレスに並ぶことになる。そのためジャンブ命令のジャンプ先のアドレスの最下位ビットは常に0である。この最下位ビットはジャンプ先のモードを示す為に利用される。両方のモードに対応したCPUではジャンプ先のアドレスの最下位ビットが0ならArmモード、1ならThumbモードに切り替わる。ブランチ命令のオペランド等は多分アセンブラがいい感じにしてくれるので単にラベルを書けば動く。ベクターテーブルのこの部分は自分で足す必要があるみたい。あんまりちゃんと調べてないのでマニュアル読んでや。</p> -<p> -この部分のセクション名は<code>.vectors</code>である。 -</p> -<h3>GPIOの設定</h3> -<p> -電源投入直後、RP2040の周辺機器はリセット状態になっている。まずは今回利用するGPIOのリセット状態を解除する必要がある。データシートの「2.14. Subsystem Resets」には以下のように書かれている: -</p> -<blockquote cite="https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf"> -<p> -Every peripheral reset by the reset controller is held in reset at power-up. -It is up to software to deassert the reset of peripherals it intends to use. -</p> -</blockquote> -<p> -リセット状態を解除するには、RESETS_BASE(<code>0x4000c000</code>)から<code>0x0</code>バイト目のRESETS: RESETレジスタのうち利用したい周辺機器のビットを<code>0x0</code>にすればいい。 -GPIOはIO Bank 0なので(これ明記されてなくない?)、RESETS: RESETレジスタのIO_BANK0(5番ビット)を<code>0x0</code>にする。 -</p> -<h4>レジスタのアトミックなクリア</h4> -<p> -RESETS: RESETレジスタのうち5番ビットだけを<code>0x0</code>にしたい。この時、まずこのレジスタを読み込んでから<code>~(1 &lt;&lt; 5)</code>と論理積を取って同レジスタに書き戻してもいいのだが、RP2040にはこれを一回の<code>str</code>でしかもアトミックにできる機能が用意されている。今回の場合アトミックかどうかは関係ないと思うけど。</p> -<p> -各レジスタには4個のアドレスが割り当てられている。データシートの各章のList of Registersに記載されているアドレスは通常の読み書きができる。そのアドレスに<code>0x1000</code>を足したものにアクセスするとアトミックなXORが、<code>0x2000</code>を足したものはアトミックなセットが、<code>0x3000</code>を足したものはアトミックなクリアができる。つまりレジスタのアドレスに<code>0x3000</code>を足したものに、<code>0x1 &lt;&lt; 5</code>を<code>str</code>すれば5番目のビットだけ<code>0x0</code>にして、他のビットは変更されない。逆に指定したビットだけ立てて他を触らない場合は<code>0x2000</code>を、あるいは指定したビットだけトグルしたい場合は<code>0x1000</code>を足したアドレスにアクセスすればいい。</p> -<h4>リセット状態の確認</h4> -<p>リセットの解除はすぐに完了するわけではないようである。リセットの解除が完了したかどうか確認するにはRESETS: RESET_DONEレジスタ(RESETS_BASEから<code>0x8</code>バイト目)の該当するビット(ここでは5番目のビット)を読む。この値が<code>0x1</code>であればリセットの解除が完了している。<code>0x0</code>であれば処理が進行中なので<code>0x1</code>が返ってくるまで繰り返し読み込んで<code>0x0</code>になるまで待機する。ところでこのレジスタはリセットの解除が完了したかどうか確かめるものなので、RESET_DONEという名前はどうなん? <p> -以上から、GPIOのリセットを解除するのは以下のコード: +入力によって変更された速度は、<code>main()</code>関数内で次の座標を計算するために使用される: </p> -<pre><code>reset: - // unreset gpio - mov r0, #1 - lsl r0, r0, #5 // io_bank0 - ldr r3, resets_base - ldr r1, atomic_clr - str r0, [r3, r1] // RESETS: RESET -reset_chk: - ldr r1, [r3, #0x8] // RESETS: RESET_DONE - tst r0, r1 - beq reset_chk +<pre><code>float px = 200, py = 200; +float vx = 0, vy = 0; +int width = 40, height = 40; -/* ... */ +int +main(void) +{ + /* ... */ + quit = 0; + while (!quit) { + handle_input() + /* ... */ + px = px + vx * dt / 1000 / 1000 / 1000; + py = py + vy * dt / 1000 / 1000 / 1000; + // bind within the window + if (px < 0) + px = 0; + if (win_width < px + width) + px = win_width - width; + if (py < 0) + py = 0; + if (win_height < py + height) + py = win_height - height; -atomic_clr: - .word 0x00003000 -resets_base: - .word 0x4000c000 + XClearArea(display, window, + 0, 0, // position + win_width, win_height, // width and height + False); + XFillRectangle(display, window, gc, + px, py, // position + width, height); // width and height + } + /* ... */ +} </code></pre> -<h3>GPIOの機能の選択</h3> -<p>RP2040のGPIOにはそれぞれ複数の機能が用意されていて、どれを使うかはソフトウェアから選択できる。利用できる機能の一覧と各機能の説明はデータシートの「2.19.2 Function Select」に詳しく書いてある。ここではGPIO25番のピンをSIO(Single-cycle IO)として利用する。同じCPUが載っているRaspberry Pi PicoはGPIO25番にLEDが半田付けされている。25番にしたのはこれに合わせるためである。他のピンでもいい。GPIOに1か0を印加するだけならこのSIOを使うみたいである。Single-cycleはCPUから操作したときに1クロックでその操作が完了するという意味らしい(本当か)。SIOの詳しい説明はデータシートの「2.3.1 SIO」にある。</p> -<p> -GPIO25番の機能を選択するにはIO_BANK0_BASE(<code>0x40014000</code>)から<code>0xcc</code>番目のGPIO25_CTRLレジスタの下位5ビットに、該当する機能の番号を書き込めばいい。データシートの「2.19.2 Function Select」にある表を見ると、GPIO25番のSIOは5である:</p> -<pre><code> // set gpio functions - ldr r3, io_bank0_base - mov r0, #5 // sio - mov r1, #0xcc - str r0, [r3, r1] // IO_BANK0: GPIO25_CTRL - -/* ... */ +<h2>完成品</h2> +<a href="https://git.mtkn.jp/xlib_playground/file/ex2/ex2.c.html">ソースコード</a> +<p>色を変えてみた。</p> +<video controls> + <source src="videos/ex2.webm" type="video/webm"> +</video> -io_bank0_base: - .word 0x40014000 -</pre></code> +<h2>参考</h2> +<ul> +<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> +</ul> +<p>次の記事: <a href="xlib_playground3.html">Xlibで遊んでみる3</a> +</p> +]]></description> +</item> +<item> +<title>Xlibで遊んでみる1</title> +<link>https://www.mtkn.jp/computer/xlib_playground1.html</link> +<guid>https://www.mtkn.jp/computer/xlib_playground1.html</guid> +<pubDate>Tue, 25 Apr 2023 00:00:00 +0900</pubDate> +<description><![CDATA[<h1>Xlibで遊んでみる1</h1> +<time>2022-12-21</time> -<h3>GPIOの出力を有効化</h3> -<p> -GPIO25番がSIOになったので、次にこのピンからの出力を有効化する。既定値では出力は無効になっている。ハイインピーダンスってことなのかな?出力を有効にするには、SIO_BASE(<code>0xd0000000</code>)から<code>0x24</code>バイト目のSIO: GPIO_OEレジスタの該当するビット(25番のピンなので25番ビット)を<code>0x1</code>にする: +<h2>はじめに</h2> +<p>X11でGUIのプログラミングをしてみようと思い、してみた。X11用の低レベルのライブラリはXlibとxcbの二つがあるようだ。x.orgのウェブページを見てみると、Xlibは古く、xcbに置きかわりつつあるという。そのため、新しくなにかを作る場合はxcbを使うようにとのことである。ところがこのxcbはドキュメンテーションに乏しく、X11を触るのが初めての人間にはなにをどうすればいいのかほとんど分からなかった。知らない関数や構造体やらがでてきても(殆ど全部知らないものだが)、その関数なり構造体なりの説明がどこにも見当たらない。manページもない。あるのはdoxygenなるものでソースコードのコメントから自動生成したいい加減なものだけで、使いものにならない。</p> +<p>とりあえずX11のことを少しは理解してからでないと初められそうもないと思い、もう少しましな情報があるXlibから始めることにした。</p> +<p>言語はC言語である。ソースコードは<a href="https://git.mtkn.jp/xlib_playground">ここ</a>にある。 </p> -<pre><code> - // enable gpio output - ldr r3, sio_base - mov r0, #1 - lsl r0, r0, #25 // gpio25 - str r0, [r3, #0x24] // SIO: GPIO_OE -/* ... */ +<h2>初期設定</h2> +<p>ディスプレイを開き、ウィンドウを作成する。変数はとりあえずグローバルに宣言することにした。<code>main</code>関数はできるだけ小さくして実際の処理はそれぞれの関数にさせてみる:</p> +<pre><code> +#include &lt;stdio.h&gt; +#include &lt;stdlib.h&gt; +#include &lt;X11/Xlib.h&gt; -sio_base: - .word 0xd0000000 -</code></pre> +/* macros */ +#define INIT_WIDTH 800 +#define INIT_HEIGHT 600 -<h3>LEDの点滅</h3> -<p>以上でGPIOの設定は完了したので、あとは実際にLEDに電圧を掛けるだけである。レジスタのアドレスに<code>0x1000</code>を足したものに書き込むとアトミックなレジスタのXORができると書いたが、SIOはこの機能がサポートされていないようである。データシートの「2.1.2 Atomic Register Access」に、 -</p> -<blockquote cite="https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf"> -<p> -The SIO (Section 2.3.1), a single-cycle IO block attached directly to the cores' -IO ports, does <strong>not</strong> support atomic accesses at the bus level, -although some individual registers (e.g. GPIO) have set/clear/xor aliases. -</p> -</blockquote> -<p> -と書かれている。そのかわりここにも書かれている通り、SIOの一部のレジスタにはアトミックなセット/クリア/XORをするためのレジスタが用意されている。ここではLEDを点滅させるためにGPIOの出力をトグルしたいのでXOR用のレジスタを使う。SIO_BASE(<code>0xd0000000</code>)から<code>0x1c</code>バイト目のSIO: GPIO_OUT_XORレジスタがそれである。このレジスタの25番ビットに<code>0x1</code>を書き込めばいい。出力をトグルした後は少し間をおいて同じことを繰り返す。間をおくためにここでは適当な数値を1づつ減らしていって0になったら返る関数<code>delay</code>を作った。タイマーと割り込みを使ったほうが消費電力等で優位なようだが、面倒なのでとりあえずこれで:</p> +/* variables */ +Display *display; +Window window; +unsigned int win_width = INIT_WIDTH, win_height = INIT_HEIGHT; +GC gc; +Atom wm_delete_window; -<pre><code> // blink led on gpio25 - ldr r4, sio_base - mov r5, r0 // r0 = 1 << 25 -loop: - str r5, [r4, #0x1c] // SIO: GPIO_OUT_XOR - bl delay - b loop +void +setup(void) +{ + // Open a display. + if ((display = XOpenDisplay(NULL)) == NULL){ + fprintf(stderr, "ERROR: could not open display\n"); + exit(1); + } + // Create a window. + window = XCreateSimpleWindow( + display, + XDefaultRootWindow(display), + 0, 0, + win_width, win_height, + 0, 0, // border properties + 0); // background color: black + XStoreName(display, window, "UNKO"); -delay: - mov r0, #1 - lsl r0, r0, #20 -delay_loop: - sub r0, r0, #1 - bne delay_loop - bx lr + // Setup a graphical context. + gc = XCreateGC(display, window, 0, NULL); + XSetForeground(display, gc, 0x0000FF); -/* ... */ + // Kill the application when the window is destroyed. + wm_delete_window = XInternAtom(display, + "WM_DELETE_WINDOW", False); + XSetWMProtocols(display, window, &wm_delete_window, 1); -sio_base: - .word 0xd0000000 -</code></pre> -<p>なお以上のコードは<code>.text</code>セクションである。</p> + // Setup which input to process. + XSelectInput(display, window, + ExposureMask|KeyPressMask|KeyReleaseMask); -<h2>リンカスクリプト</h2> -<p> -以上のコードには<code>.boot2</code>、<code>.vectors</code>、<code>.text</code>の3つのセクションが含まれる。<code>.boot2</code>はフラッシュの先頭から256(<code>0x100</code>)バイト目まで、<code>.vectors</code>と<code>.text</code>はその後ろに続くように配置する: -<pre><code>MEMORY -{ - FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k + // Actually draw the window. + XMapWindow(display, window); } -SECTIONS +void +clean_up(void) { - .boot2 : { - *(.boot2) - . = 0x100; - } > FLASH - - .text : { - *(.vectors) - *(.text) - } > FLASH + XCloseDisplay(display); } </code></pre> -<h2>Makefile</h2> -<p> -以上のソースコードは以下のように配置している: -</p> -<pre><code>rp2040 -├── ex1 -│   ├── Makefile -│   ├── boot2.s -│   ├── main.s -│   └── memmap.ld -└── tools - ├── Makefile - ├── bin2uf2.c - └── bincrc.c -</code></pre> -<p> -toolsディレクトリのMakefileは同じディレクトリのソースファイルを<code>$(CC)</code>でコンパイルするだけのものである(個人的な趣味で<code>tcc</code>を使っている)。ex1ディレクトリのMakefileは以下の通り: -</p> -<pre><code>AS = arm-none-eabi-as -LD = arm-none-eabi-ld -OBJCOPY = arm-none-eabi-objcopy -BINCRC = ../tools/bincrc -BIN2UF2 = ../tools/bin2uf2 - -MCPU = -mcpu=cortex-m0plus -ASFLAGS = $(MCPU) -CFLAGS = $(MCPU) -ffreestanding -nostartfiles -O0 -fpic -mthumb -c -LDFLAGS = --no-relax -nostdlib - -all: tools led.uf2 - -clean: - rm -f *.o *.elf *.uf2 *.bin - cd ../tools &amp;&amp; make clean - -.s.o: - $(AS) $(ASFLAGS) -o $@ $&lt; - -led.elf: boot2.o main.o memmap.ld - $(LD) $(LDFLAGS) -o $@ -T memmap.ld boot2.o main.o +<p>適当な四角形のものを表示し、その位置を時間の関数として動かしてみる。</p> +<pre><code>#include &lt;time.h&gt; +#include &lt;math.h&gt; -led.bin: led.elf - $(OBJCOPY) -O binary led.elf $@ +int +main(void) +{ + int px, py; + int quit; + struct timespec ts; + XEvent event; -led.uf2: led.bin - $(BINCRC) led.bin led_crc.bin - $(BIN2UF2) led_crc.bin $@ + setup(); + quit = 0; -flash: all - mount /dev/disk/by-label/RPI-RP2 /mnt - cp led.uf2 /mnt + while (!quit){ + while(XPending(display) > 0){ + XNextEvent(display, &event); + switch (event.type){ + case KeyPress: { + switch (XLookupKeysym(&event.xkey, 0)){ + case 'q': + quit = 1; + break; + default: + break; + } + } break; + case ClientMessage: { + if ((Atom) event.xclient.data.l[0] == wm_delete_window) { + quit = 1; + } + } break; + default: + break; + } + } + clock_gettime(CLOCK_MONOTONIC, &ts); + px = 200 + (int) (100 * sinf(ts.tv_sec + ts.tv_nsec / 1000.0 / 1000 / 1000)); + py = 200 + (int) (100 * cosf(ts.tv_sec + ts.tv_nsec / 1000.0 / 1000 / 1000)); + XClearArea(display, window, + 0, 0, // position + win_width, win_height, // width and height + False); + XFillRectangle(display, window, gc, + px, py, // position + 100, 100); // width and height -tools: - cd ../tools &amp;&amp; make -</code></pre> + ts.tv_sec = 0; + ts.tv_nsec = 10 * 1000 * 1000; + nanosleep(&ts, NULL); + } -<p> -RP2040のボードをUSBデバイスモードでLinuxのパソコンに接続し、ex1ディレクトリで</p> -<pre><code>$ make -# make flash + cleanup(); + return 0; +} </code></pre> -<p> -とすればプログラムがRP2040のボードに書き込まれて実行が開始される。</p> -<h2>最後に</h2> -<p> -光あれ。 -</p> +<p>ここまでのコードはgitリポジトリの<a href="https://git.mtkn.jp/xlib_playground/file/ex1/ex1.c.html">ex1/ex1.c</a>にある。</p> +<h2>完成品:</h2> +<video controls> + <source src="videos/ex1.webm" type="video/webm"> +</video> <h2>参考</h2> <ul> -<li> -[1] Hennesy, J. L. and Patterson, D. A. 2017. Computer Organization And Design RISC-V Edition. -</li> -<li> -[2] <a href="https://akizukidenshi.com/catalog/g/gK-17542/">RP2040マイコンボードキット.秋月電子通商</a> -</li> -<li> -[3] <a href="https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf">RP2040 Datasheet.Raspberry Pi Foundation</a> -</li> -<li> -[4] <a href="https://github.com/raspberrypi/pico-sdk">pico-sdk.github</a> -</li> -<li> -[5] <a href="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB">巡回冗長検査.Wikipedia</a> -</li> -<li> -[6] <a href="https://github.com/microsoft/uf2">USB Flashing Format (UF2).GitHub</a> -</li> -<li> -[7] <a href="https://developer.arm.com/documentation/ddi0419/c/">ARMv6-M Architecture Reference Manual</a> -</li> +<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> +<li><a href="https://www.youtube.com/watch?v=764fnfEb1_c">X11 App in C with Xlib(youtube video by tsoding)</a></li> </ul> + +<a href="xlib_playground2.html">次の記事</a> ]]></description> </item> <item> diff --git a/pub/sitemap.xml b/pub/sitemap.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url><loc>https://www.mtkn.jp/</loc><lastmod>2023-12-28</lastmod></url> +<url><loc>https://www.mtkn.jp/computer/rp2040_1.html</loc><lastmod>2023-05-09</lastmod></url> <url><loc>https://www.mtkn.jp/computer/what-i-use.html</loc><lastmod>2023-05-02</lastmod></url> <url><loc>https://www.mtkn.jp/computer/xlib_playground6.html</loc><lastmod>2023-04-25</lastmod></url> <url><loc>https://www.mtkn.jp/computer/xlib_playground5.html</loc><lastmod>2023-04-25</lastmod></url> @@ -8,7 +9,6 @@ <url><loc>https://www.mtkn.jp/computer/xlib_playground3.html</loc><lastmod>2023-04-25</lastmod></url> <url><loc>https://www.mtkn.jp/computer/xlib_playground2.html</loc><lastmod>2023-04-25</lastmod></url> <url><loc>https://www.mtkn.jp/computer/xlib_playground1.html</loc><lastmod>2023-04-25</lastmod></url> -<url><loc>https://www.mtkn.jp/computer/rp2040_1.html</loc><lastmod>2023-04-25</lastmod></url> <url><loc>https://www.mtkn.jp/computer/</loc><lastmod>2023-04-25</lastmod></url> <url><loc>https://www.mtkn.jp/poetry/</loc><lastmod>2023-03-21</lastmod></url> <url><loc>https://www.mtkn.jp/journal/posts/20230119.html</loc><lastmod>2023-01-19</lastmod></url> diff --git a/temp/header.html b/temp/header.html @@ -1,10 +1,10 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width,initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="/style.css" /> - <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> <title><!--title--></title> </head> <body>