"Entropi, sumber ergodik, ruang pesan multidimensi, bit, polisemi, proses Markov - semua kata-kata ini terdengar sangat mengesankan, dalam urutan apa pun mereka ditempatkan. Jika Anda mengaturnya dalam urutan yang benar, mereka memperoleh konten teoretis tertentu. Dan seorang spesialis sejati terkadang dapat menemukan solusi untuk masalah praktis sehari-hari dengan bantuan mereka. "
John PIRS "I See No Evil"
Posting ini penuh dengan diskusi tentang optimalisasi operasi matematika pada MK dengan sumber daya terbatas, serta penilaian subyektif dari berbagai aspek pengembangan perangkat lunak tertanam.
Orang-orang yang peringatan ini tidak menakutkan, saya bertanya di bawah kucing.
Sebelum kita menjelaskan prosedur untuk mengekstrak akar kuadrat dari bilangan bulat, operasi terbalik menjadi kuadrat dan, karenanya, mengalikan, mari kita bicara tentang yang terakhir.
Misalkan kita memiliki kesempatan untuk mengalikan angka 8-bit dengan angka 8-bit, mendapatkan hasil 16-bit (8 * 8 = 16), bagaimana kita bisa mendapatkan implementasi operasi 16 * 16 = 32 berdasarkan operasi ini. Cara yang jelas adalah mewakili 16 sebagai jumlah dari dua 8, lalu kita dapatkan
(16)*(16)=(1(8)*256+2(8))*1(8)*256+2(8)) =1*1*256*256+1*2*256+2*1*256+2*2
Jika dalam ekspresi yang dihasilkan kami mengganti perkalian dengan 256 dengan shift kiri dengan 8 digit, maka kami mendapatkan algoritma yang sepenuhnya berfungsi. Mari kita perkirakan waktu yang dihabiskan untuk implementasi - kita perlu 4 perkalian 8 * 8 = 16 dan 4 tambahan dari angka 4 byte 32 + 32 = 32. Untuk tipe MK AVR, kami mendapatkan 4 * 2 + 4 * 4 = 24 siklus, tapi ini untuk solusi "dahi". Mari kita coba tingkatkan hasilnya. Fakta bahwa kita tidak perlu 4, tetapi 3 penambahan dan satu penugasan agak menyederhanakan situasi, karena penomoran awal hasil tidak diperlukan, tetapi kami masih tidak memperhitungkannya, meskipun itu perlu dan total waktu harus 24 + 4 = 28 siklus. Tetapi, jika kita memperhitungkan adanya pergeseran dalam tiga istilah pertama (masing-masing, kita memiliki bahwa rendah (dua byte rendah) adalah nol dan tidak ada gunanya menambahkannya ke hasil), maka kita harus menambahkan bukan 4 byte, tetapi tiga dan dua, yang akan mengurangi waktu eksekusi untuk 1 * 2 + 2 = 4 langkah dan dapatkan 20 langkah. Selanjutnya, kita dapat memperhatikan fakta bahwa istilah pertama dan terakhir tidak berpotongan sama sekali, yang memungkinkan kita untuk mengganti penomoran dari bagian tertinggi dari hasil dengan penugasan istilah pertama dan mengurangi waktu eksekusi oleh siklus 2 jam ke 18. Selanjutnya, dengan menggunakan fitur arsitektur, yaitu kehadiran perintah transfer register berpasangan, simpan dua ukuran lebih dan hasil akhir - 16 ukuran bukannya 28 asli - agak, tapi bagus.
Metode optimasi serupa bekerja untuk operasi 32 * 32 = 32, di mana Anda dapat mengurangi waktu eksekusi dari yang diharapkan 4 * 4 * (2 + 4) + 4 = 100 siklus clock menjadi (3 + 5 + 4 + 3) + (5 + 3 +3) + (4 + 3) + 3 = 36 tindakan, yang tidak buruk sama sekali. Nah, pada akhir pertimbangan berbagai opsi untuk perkalian, kami mencatat bahwa 16 * 16 = 16 dapat diperoleh dalam 3 + 3 + 3 = 9 siklus. Perhatikan bahwa semua pertimbangan ini hanya valid dengan asumsi bahwa ada operasi 8 * 8 = 16 untuk 2 langkah, dan jika tidak pada target MK, waktu pelaksanaan semua versi operasi yang lain pasti tidak akan menjadi lebih cepat.
Mari kita meringkas waktu yang diperlukan untuk melakukan perkalian (8 * 8 = 8 2, 8 * 8 = 16 9, 16 * 16 = 16 16, 16 * 16 = 32 36) dan sekarang mempertimbangkan masalah aslinya.
Kita perlu mengekstrak akar integer kuadrat dari angka 32 bit H, yaitu, menemukan angka 16 bit terbesar sehingga n * n <= H. Kita semua dari kursus sekolah menengah tahu metode perkiraan berturut-turut ke akar kuadrat (n = (N / n '+ n) / 2), tetapi ketika menggunakannya kita harus membagi bilangan bulat, dan ini adalah operasi yang sangat memakan waktu.
Oleh karena itu, skema perhitungan lainnya dikembangkan, salah satunya adalah metode pendekatan bitwise, yang dalam pseudo-code terlihat sebagai berikut:
- nilai awal -> n = 0; b = 0x8000;
- lakukan 16 kali -> jika ((n + b) * (n + b)> = H) n = n + b; b = b >> 1;
Anda dapat segera memperkirakan waktu yang dihabiskan untuk opsi ini 16 (jumlah bit hasil) * (2 (organisasi siklus) +2 (penambahan) + X (penggandaan) +5 (perbandingan dan solusi) +2 (modifikasi hasil) / 2 (rata-rata hasil) setengah waktu) +2 (bit shift)) = 16 * (12 + X). Anda bertanya mengapa dalam rumus X bukan angka 16, dan ternyata penyergapan menunggu kami, karena kami menulis dalam C, dan bukan dalam assembler. Faktanya adalah bahwa di perpustakaan standar tidak ada operasi perkalian dengan perubahan kedalaman bit dan kami tidak dapat menerapkan 16 * 16 = 32, tetapi dipaksa untuk menggunakan 32 * 32 = 32, yang mengarah ke X = 36 bukannya X = 16 dan angka terakhir adalah 16 * 48 = 768 siklus clock untuk mengekstraksi nilai integer dari akar kuadrat dari angka 32-bit.
Tentu saja, ini jauh lebih baik daripada metode Newton, tetapi sedikit banyak, mari kita lihat apa yang bisa dilakukan.
Jadi, jelas bahwa sebagian besar waktu dihabiskan untuk menghitung hasil perkalian berikutnya. Tentu saja, Anda dapat menulis ulang dalam assembler dan menggunakan versi perkalian yang lebih murah, mendapatkan 16 * (12 + 16) = 448 kutu, tetapi kami akan meninggalkan cara ini sebagai pilihan terakhir. Pertimbangkan prosesnya dengan lebih hati-hati dan lihat bahwa kita tidak menghitung perkalian dari angka acak dengan sendirinya, tetapi perkalian dari nilai sebelumnya dengan beberapa peningkatan, dan kuadrat dari nilai sebelumnya diketahui. Oleh karena itu, kita dapat menggunakan skema perbedaan berdasarkan rumus (n + b) * (n + b) = n * n + 2 * n * b + b * b. Pada pandangan pertama, ini terlihat seperti ejekan - alih-alih satu perkalian, kita perlu melakukan empat bagian dan bahkan dua penambahan angka panjang (32-bit). Tapi mari kita mulai mengerti: kita sudah memiliki n * n, b * b dengan mempertimbangkan bahwa b = b '/ 2 mudah diperoleh, seperti b' * b '/ 4, dan juga 2 * n * b = 2 * n * b '/ 2.
Skema perhitungan berikut muncul:
- nilai awal -> nn = 0; n = 0; b = 0x8000; bb = b * b;
- ulangi 16 kali -> jika (nn + n + bb> = H) {n = n + b; nn = nn + bb + n}; bb >> 2; b> 1;
Kami memperkirakan biaya implementasi 16 * (2 (organisasi siklus) +12 (penugasan dan dua tambahan) +5 (perbandingan dan solusi) + (2 (penambahan) +8 (dua tambahan)) / 2 (rata-rata setengah waktu) +8 (bergeser ke kanan dengan 2) +2 (bergeser ke kanan) = 16 * 34 = 544 siklus clock. Lebih baik daripada dengan perkalian yang salah dari 32 * 32, tapi kami masih memiliki cadangan.
Apa yang mereka - mari kita perhatikan operasi yang paling mahal - menambah dan membandingkan total 17 siklus clock dan mengulang kembali loop utama dari algoritma:
2. ulangi 16 kali -> T = H-bb-n; if (T> = 0) {H = T; n = n + b);}; bb >> 2; b> 1;
Maka waktu pelaksanaan siklus akan 16 * (2 (organisasi siklus) +12 (perhitungan perbedaan baru) +1 (perbandingan dan solusi) + ((4 (tugas) +2 (penambahan)) / 2 (rata-rata setengah waktu) +8 +2) = 16 * 28 = 448 siklus, jika Anda memperhitungkan kekhasan arsitektur, Anda dapat menyimpan 2 + 2 = 4 * 16 = 64 siklus yang lain dan menyimpannya dalam waktu kurang dari 400 siklus.
Kami mendapatkan hasil yang sedikit lebih baik, seperti ketika menggunakan perkalian yang benar 16 * 16 = 32, tetapi tanpa assembler, "dalam C murni". Namun, ada minus yang signifikan - jika semuanya intuitif dalam versi dengan perkalian, maka varian dengan skema perbedaan tanpa komentar memberikan kesan sesi sihir hitam, Anda harus memilih. Perhatikan juga bahwa kami menukar jumlah pengukuran untuk memori tambahan untuk variabel perantara, yang biasanya terjadi.
Catatan yang diperlukan - kami tidak mendapatkan keuntungan (kadang-kadang) yang signifikan dibandingkan dengan multiplikasi, karena kami memiliki implementasi cepat 8 * 8 = 16. Jika tidak ada dalam MK (dan ini terjadi) atau tidak begitu cepat (dan ini juga terjadi), maka skema perbedaan menjadi beberapa kali lebih cepat, karena hanya menggunakan operasi penambahan dan pengalihan standar, yang dijamin berada dalam MK mana pun.
Tampaknya itu tidak akan bekerja lebih baik, tetapi, ternyata, masih ada cadangan untuk meningkatkan kinerja algoritma. Mari kita coba menggunakan metode percepatan klasik lain - bagilah dan taklukkan. Bagaimana jika Anda pertama kali mengekstrak akar kuadrat dari bagian argumen yang lebih lama, dan kemudian memperbaikinya? Pertama-tama, kami menunjukkan bahwa ini pada dasarnya mungkin. Memang, kami menyajikan argumen dalam bentuk H = H '<< 16 + H' 'dan hasilnya dalam bentuk n = n' << 8 + n ''. Karena n '' <256, maka kuadratnya jelas akan kurang dari kuadrat dari angka n = n '<< 8 + 256 = (n' + 1) << 8. Oleh karena itu, bagian tertinggi dari hasil tidak melebihi akar kuadrat dari bagian tertinggi dari argumen.
Implementasi pendekatan ini diserahkan kepada pembaca yang ingin tahu.
Apa yang akan diberikan pendekatan ini kepada kita, karena jumlah total iterasi akan tetap tidak berubah - kita dapat melakukan paruh pertama iterasi dengan jumlah panjang yang lebih pendek, dan ini mengarah pada penurunan biaya waktu. Pendekatan ini dapat diterapkan pada varian dengan multiplikasi dan varian perbedaan, total keuntungan akan mencapai seperempat dari total waktu eksekusi.
Catatan yang diperlukan - penerapan pendekatan ini sama sekali tidak jelas, ketika menerapkan untuk MK seperti AVR, akselerasi eksekusi memang terjadi, tetapi untuk beberapa arsitektur, misalnya untuk x86, perlambatan operasi muncul secara tak terduga. Rupanya, bekerja dengan data non-asli (16 bit) dalam arsitektur ini secara signifikan lebih mahal dalam waktu daripada dengan asli (32 bit). Saya tidak melakukan penelitian mendalam, tetapi fakta itu terjadi dan saya harus melaporkannya untuk menghindari kesalahpahaman.
Tapi itu belum semuanya. Karena kita telah memulai jalan pemisahan dan penguasaan, maka mengapa tidak melangkah lebih jauh - ekstrak akar dari bit langkah demi langkah, dimulai dengan yang tertua (dimulai dengan yang lebih muda kontraproduktif dalam kasus kami). Skema algoritma adalah sama - kami menambahkan bagian bit berikutnya dalam hasil saat ini dan mencoba menambahkan bit berikutnya ke hasilnya, memeriksa apakah kami telah melampaui nilai root. Keunikannya adalah kita hanya dapat memeriksa bit argumen yang tinggi, sampai kita mendapatkan bit yang rendah.
Saat menerapkan, kami menggunakan satu trik lagi - alih-alih memindahkan angka yang kami kurangi ke kanan, kami akan memindahkan argumen yang dikurangi ke kiri, artinya tidak berubah, dan kecepatan bertambah. Ini meningkat karena dua faktor - 1) cukup bagi kita untuk mengurangi hanya 16 bit (ada satu kekhasan, dan itu harus diperhitungkan, tetapi kita sedang mempertimbangkan studi kasus, vout) dan 2) kita tidak perlu menggeser kuadrat dari bit berikutnya, karena akan selalu ada sama dengan satu. Tetapi Anda harus membayar semua yang ada di dunia ini dan kami akan memiliki pergeseran perbedaan yang diperluas (6 byte) ke kiri, dan 2 bit per jam. Kami melihat kode semu
- nilai awal -> n = 0; H1 = 0;
- ulangi 16 kali -> (H1, H) << 2; T = H1-n-1; if (T> 0) {H1 = T; n = n + 2}; n << 1;
dan evaluasi waktu eksekusi, dapatkan 16 * (12 (shift diperpanjang) +4 (menghitung perbedaan) +1 (solusi) +2 (tugas) +1 (meningkat) +2 (shift)) = 16 * 22 = 352 langkah, mungkin , hasilnya hampir sempurna. Ketika menerapkan opsi ini, ada jebakan kecil, saya menyerahkan ini lagi kepada pembaca yang ingin tahu (well, dia mendapatkan pekerjaan).
Nah, pada kesimpulan bagian yang mendorong saya untuk menulis posting ini. Ada perpustakaan McuCpp yang benar-benar luar biasa, yang ditulis oleh Anton Chizhov, di mana, berdasarkan pada kelas lokus kepenulisan, Andriescu sangat luar biasa elegan (well, sejauh keanggunan dapat diterapkan ke templat C ++), bekerja dengan pin <a «
github.com/KonstantinChizhov/ Mcucpp »Saya sangat menghormati penulis yang disebutkan (keduanya) dan baru-baru ini, sehubungan dengan keadaan, yang akan saya bahas nanti, saya melihat sumber perpustakaan ini dan sekali lagi mengagumi.
Namun, di antara file-file lain saya melihat template_utils.h, di mana beberapa rutin tambahan diimplementasikan, dan di antara mereka sebuah akar integer dari nomor 32-bit. Fakta bahwa ia menggunakan algoritma pendekatan sekuensial paling sederhana dengan perkalian tidak menakutkan, karena algoritma ini tidak kehilangan begitu banyak dalam kecepatan, tetapi dalam pemahaman itu memberikan banyak poin di depan dan masih menang. Tetapi saya tidak terlalu suka fakta bahwa itu dilaksanakan agak tidak akurat (dalam hal kinerja), karena "anak-anak dapat melihatnya." Ketidaktepatan terdiri dari mewakili angka yang dipilih dengan 32 bit, karena kita tahu dengan pasti bahwa akar dari angka 32 bit tidak akan melampaui 16 bit, jadi mengapa kita perlu menggeser nol byte. Dan inilah yang terjadi ketika kompiler itu sendiri tidak akan pernah menebak untuk melakukan optimasi dan harus membantunya.
Konversi fungsi yang jelas
static inline uint32_t sqrt(uint32_t value) { uint16_t result = 0; uint16_t add = 0x8000; for (uint8_t i = 16; i !=0; ++i) { uint32_t rootGuess = result | add; uint32_t guess = rootGuess * rootGuess; if (value >= guess) { result = rootGuess; } add >>= 1; } return result; }
memungkinkan kita untuk menyimpan 2 siklus pada sedikit pergeseran dan 2 siklus menciptakan faktor berikutnya pada setiap siklus, dan mengatur siklus dalam bentuk yang ditentukan adalah 4 siklus lainnya (saya tahu bahwa kompiler dapat melakukan optimasi ini untuk kita, tetapi mengapa tidak membantu secara eksplisit ), yang cukup baik untuk perubahan kode kosmetik murni yang tidak memengaruhi kelengkapannya sedikit pun.
Catatan kemudian - satu komentar membuat saya berpikir bahwa itu akan lebih benar
for (uint_fast8_t i= ...)
Terima kasih Oleg atas bantuannya.
Ceri pada kue adalah fungsi mengekstraksi seluruh akar kuadrat dari nomor tanda yang terletak tepat di bawah, yang mengklaim sebagai √-1 = 65635 = -1. Di sisi lain, mengapa tidak, apa yang lebih buruk daripada hasil lainnya, ini tidak terkecuali bagi kami Penyebab di MK, dan seluruh akar kuadrat dari angka negatif tidak ada.
Nah, kesimpulan tentang mengapa saya menoleh ke perpustakaan Anton Chizhov. Saya diminta oleh sebuah pos baru-baru ini mengenai RTOS domestik untuk MK dengan nama MAX (MultiAgent Coherent System) - lihat epigraf ke pos yang diiklankan oleh pembuatnya dan diangkut ke MK yang diproduksi oleh Milander. Catatan - posting ini sama sekali bukan materi promosi dan akan segera menjadi jelas bagi pembaca. Dari mcucpp yang disebutkan di atas, penulis OS menggunakan implementasi buffer cincin (sama sekali tidak meremehkan kelebihan perpustakaan Anton, saya harus mengatakan bahwa bagian ini bukan referensi, dan ini masih merupakan perumusan yang lembut, yang saya tulis di pos lain yang saya tidak akan posting sama sekali). Karena saya bekerja erat dengan fasilitas produksi Milander, materi tersebut menarik minat saya dan saya mengikuti tautan ke situs web pengembang.
Di sinilah tangisan Yaroslavna selanjutnya.
Tahun lalu, ketika pembuatan RTOS domestik pertama kali diumumkan, saya mengunduh deskripsi produk perangkat lunak dari situs ini, tetapi entah bagaimana tangan saya tidak mencapai studi. Dengan sifat aktivitas saya, saya harus berurusan dengan komponen domestik (saya cukup mengerti ...), jadi akan menyenangkan untuk memiliki perangkat lunak yang sesuai. Mengingat bagaimana dalam rilis tahun lalu, direktur perusahaan berbicara tentang jutaan rubel yang dihabiskan untuk pengembangan dan tim besar yang bekerja pada pembuatan produk perangkat lunak ini, saya memutuskan untuk melihat versi uji coba yang tersedia untuk diunduh secara gratis, dan di sini saya membagikan hasilnya.
Pertama-tama, deskripsi selama setengah tahun hampir setengahnya dalam volume (dari 115 menjadi 55 halaman), dan jika hilangnya aplikasi dengan tangkapan layar yang menjelaskan proses peluncuran produk ketiga dari "Deskripsi Program" disambut, maka bukan tampilan dari bahan-bahan ini (untuk pembuatan yang Saya menghabiskan, meskipun tidak terlalu signifikan, tetapi masih waktu dan uang) dalam dokumen seperti "Panduan Operator" Saya pribadi bingung. Lebih jauh, dalam frasa pertama dokumen tersebut, kita melihat penyimpangan yang jujur dari kebenaran, karena RTOS sendiri tidak dimaksudkan untuk "membuat program" dengan cara apa pun, untuk beberapa alasan penulis tidak membiarkan diri mereka pernyataan seperti itu dalam versi dokumen sebelumnya, pengaruh layanan pemasaran dirasakan. Ini juga memberikan bahwa jika deskripsi dulu berada di folder / docs dari direktori root, dan ini logis, sekarang tersembunyi di / toolchain / macs / docs, well, seperti yang mereka katakan di masa muda saya, "semua orang marah dengan caranya sendiri," kita melanjutkan.
Saya mulai melihat uraiannya, melihat kode sumbernya (termasuk dalam versi uji coba) dan dalam kebingungan saya menemukan tidak adanya driver perangkat periferal yang diadaptasi untuk bekerja dengan OS ini. Pertama saya menyarankan bahwa ini adalah fitur percobaan, kemudian pada forum di informasi dari pengembang saya menemukan bahwa sebenarnya tidak ada driver, tetapi mereka sedang mengusahakannya. Lebih dari enam bulan (enam bulan, Carl, sebenarnya hampir satu tahun) dari saat OS dirilis untuk MK, dan mereka bekerja pada driver. Secara alami, atau seperti yang mereka katakan, tak perlu dikatakan bahwa tidak ada pembicaraan tentang produk ketiga (sistem file, tumpukan jaringan, tumpukan USB). Sebuah ide lucu dari penulis tentang persyaratan untuk pengembangan perangkat lunak untuk MK, oke, melaju lagi.
Yaitu, OS yang dideklarasikan, fitur yang disorot di antaranya adalah organisasi interaksi dalam sistem multi-controller, tidak memiliki cara asli untuk mengatur interaksi ini. Apa yang kami miliki di garis bawah - dan kami memiliki manajemen tugas, sebenarnya sheduler, layanan waktu minimal dan sarana sinkronisasi tugas, dan itu saja - lucu, untuk sedikitnya. Oke, kita akan melihat lebih jauh, bahkan dalam serangkaian komponen solusi yang menarik dimungkinkan, terutama ketika Anda mempertimbangkan bahwa di satu situs (bukan perusahaan pabrikan) saya melihat "pemeriksaan" kode sumber OS ini dengan referensi. Dokumen ini mengatakan bahwa produk perangkat lunak tidak menggunakan komponen pihak ketiga (impor) dan asli, perlu untuk dipastikan.
Pengamatan pertama adalah bahwa jika Anda menggunakan file ARM asli yang termasuk dalam paket kode sumber untuk port ke arsitektur Cortex-M0 tertentu (1986 BE1T), maka ini sangat mirip dengan menggunakan fragmen teks pihak ketiga (yang diimpor) - Saya pribadi berpikir bahwa ini adalah penggunaannya, tetapi Saya mungkin tidak tahu segalanya. Nah, dan kedua, kode sumber sheduler dan komponen manajemen tugas terkait benar-benar asli dan tidak memiliki analog (setidaknya saya tidak tahu), tetapi ini adalah jenis orisinalitas ketika saya mengingat ungkapan dukun lama dari film "The Evil Spirit of Yambuya" tentang pemburu ulung: "Potong telinganya, masak dan makan - apakah kamu bisa menebak?"
Saya akan mencoba menjelaskan - dalam desain OS secara umum dan dalam RTOS khususnya, salah satu masalah kompleks adalah masalah memastikan akses semua proses dalam sistem ke sumber daya bersama - runtime prosesor. , ( ) , . ( , , MPU), .
, , , , . (1) , , FREE-RTOS 20 , ( , , ).
Oleh karena itu, saya sedikit terkejut menemukan bahwa OS yang dimaksud memungkinkan Anda memiliki hingga 60 prioritas (dan bahkan lebih). Kejutan itu tersebar ketika saya melihat melalui sumber. Alih-alih memisahkan antrian tugas dengan prioritas yang sama, penulis menggunakan satu antrian (ada juga antrian kedua dari tugas yang diblokir) yang siap untuk pelaksanaan tugas, yang membantu menghemat memori (mungkin ini adalah tujuan dari solusi semacam itu) karena fakta bahwa- operasi menambahkan tugas ke antrian menjadi O (n) dan
- ini membuat penggunaan sheduler yang dimodifikasi menjadi tidak mungkin - menurut saya, sedikit mahal untuk 20 * (3 * 4) = 240 byte RAM. Solusinya luar biasa orisinal, tetapi, dari sudut pandang saya, ini adalah satu-satunya keuntungan.
Secara umum, saya masih tidak mengerti mengapa penulis akan mengambil uang (tetapi mereka masih belum memutuskan apakah akan melakukan ini, dilihat dari forum) dan solusi serta fitur tertentu yang memungkinkan untuk memberikan perangkat lunak dengan nama yang luar biasa. Terutama mengingat berapa banyak perangkat lunak yang disediakan secara gratis oleh banyak pemasok MK (tentu saja, yang diimpor). Saat menelusuri forum perusahaan dalam upaya untuk menemukan jawaban, saya melihat referensi ke produk perangkat lunak mcucpp yang disebutkan sebelumnya (penulis MAKS diduga terinspirasi oleh ide-ide Chizhov - tiga kali ha), di mana saya menemukan cacat kecil yang dijelaskan di atas.— - , .
(, , ) - — . ( , , ), , ( 2013) 1 , 2019 .
, :
- ( , ) ( , , , , ),
- ( ),
- () 2,
- HAL, CMSIS (- ),
- ,
- ,
- (3rd part), ,
- ,
- ,
- , (, , ..) « »,
- , , ( , , MIT , « »), , (?).
Tentu saja, semua ini tidak muncul dengan sendirinya dan membutuhkan biaya, tetapi bagi saya tampaknya perusahaan tingkat Anda mampu membayar pekerjaan 5 orang selama enam bulan untuk membuat semua hal di atas (dengan pengecualian klausa, mungkin klausul 10, meskipun sekarang semua signifikan dan banyak produsen MK kecil mendapat IDE sendiri). Jika ini disadari, maka tanah akan hilang untuk penampilan kerajinan seperti OS yang dijelaskan dalam posting ini.Meskipun mungkin saya tidak tahu sesuatu, dan sebenarnya semuanya tidak sesederhana itu, sangat disayangkan jika ini benar-benar terjadi.Saya minta maaf sebelumnya jika catatan saya tampak terlalu keras, itu Anda (Milander) yang saya tidak ingin menyinggung.