{"id":327993,"date":"2022-01-14T09:00:30","date_gmt":"2022-01-14T09:00:30","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=327993"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=327993","title":{"rendered":"<span>\u041f\u0438\u0448\u0435\u043c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 Game Boy \u043d\u0430 OCaml<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/webt\/s7\/wu\/eh\/s7wuehzqqlfkr5xqnzuaqsnmbdw.png\"\/><\/div>\n<p>  <\/p>\n<h1>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h1>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <em>CAMLBOY<\/em> \u2014 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c Game Boy, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u043d\u0430 OCaml, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u041f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0434\u0435\u043c\u043e:<\/p>\n<p>  <strong><a href=\"https:\/\/linoscope.github.io\/CAMLBOY\/\" rel=\"nofollow noopener noreferrer\">\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0434\u0435\u043c\u043e<\/a><\/strong><\/p>\n<p>  \u042f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0432 \u0434\u0435\u043c\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 ROM, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c (\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e <em>Bouncing ball<\/em> \u0438 <em>Rocket Man Demo<\/em>). \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c \u0432 \u043d\u0438\u0445 \u0432 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043d\u0430 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u043c\u0430\u0440\u0442\u0444\u043e\u043d\u0430\u0445 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 60 FPS.<\/p>\n<h2>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/h2>\n<p>  \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0437\u0434\u0435\u0441\u044c:<\/p>\n<p>  <strong><a href=\"https:\/\/github.com\/linoscope\/CAMLBOY\" rel=\"nofollow noopener noreferrer\">https:\/\/github.com\/linoscope\/CAMLBOY<\/a><\/strong><br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u044b<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/c54\/757\/6a0\/c547576a007699574417cb451f7d403c.gif\"\/><\/div>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/025\/50c\/61c\/02550c61cc5dd99b160e60745e0ec2d7.gif\"\/><\/div>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/02e\/ab6\/5b0\/02eab65b055d4363741b63a3ebfeb12c.gif\"\/><\/div>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/e0f\/3dc\/52f\/e0f3dc52fc8928b6f5c06dcadd0b678c.gif\"\/><\/div>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/1ec\/4c2\/1e8\/1ec4c21e811ffd2289e0b6414e291486.gif\"\/><\/div>\n<\/div><\/div>\n<p>  <\/p>\n<h2>\u0417\u0430\u0447\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 Game Boy \u043d\u0430 OCaml?<\/h2>\n<p>  \u0412\u044b \u043a\u043e\u0433\u0434\u0430-\u043d\u0438\u0431\u0443\u0434\u044c \u0438\u0441\u043f\u044b\u0442\u044b\u0432\u0430\u043b\u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u043f\u0440\u0438 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f?<\/p>\n<ul>\n<li>\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u0434\u0430, \u043d\u043e <strong>\u043d\u0435 \u0437\u043d\u0430\u0435\u0442\u0435, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e\/\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0430<\/strong>. [\u041f\u043e\u0434 \u044d\u0442\u0438\u043c \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u00ab\u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043b\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0431\u0435\u0437 \u0442\u0435\u0441\u0442\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\u00bb. \u0422\u0435\u043c\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043b\u0435\u0433\u043a\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0440\u0435\u0434\u043a\u043e \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043a\u043d\u0438\u0433\u0430\u0445, \u043d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043e\u043d\u0430 \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u0430.]<\/li>\n<li>\u0412\u044b \u0438\u0437\u0443\u0447\u0438\u043b\u0438 <strong>\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u044f\u0437\u044b\u043a\u0430 \u0438 \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442<\/strong>, \u043d\u043e <strong>\u043d\u0435 \u0437\u043d\u0430\u0435\u0442\u0435, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435<\/strong>. [\u041f\u043e\u0434 \u00ab\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u043c\u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u044f\u0437\u044b\u043a\u0430\u00bb \u0432 OCaml \u044f \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u044e \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u044b, GADT, \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 (first-class module) \u0438 \u0442. \u043f.] <\/li>\n<\/ul>\n<p>  \u0418\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u044f \u0434\u0443\u043c\u0430\u043b, \u043a\u043e\u0433\u0434\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043d\u0430\u0437\u0430\u0434 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043b \u043a \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044e OCaml. \u042f \u043f\u043e\u043d\u0438\u043c\u0430\u043b \u043e\u0441\u043d\u043e\u0432\u044b \u044f\u0437\u044b\u043a\u0430 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0447\u0442\u0435\u043d\u0438\u044e \u043a\u043d\u0438\u0433 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432, \u043d\u043e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0435 \u0432\u044b\u0448\u0435 \u0434\u0432\u0430 \u043f\u0443\u043d\u043a\u0442\u0430 \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u043b\u0438 \u043c\u043d\u0435 \u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u044f <em>\u043f\u043e-\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u043c\u0443<\/em> \u043c\u043e\u0433\u0443 \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430 OCaml. \u042f \u0437\u043d\u0430\u043b, \u0447\u0442\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u044d\u0442\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0447\u0430\u043b \u0438\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442, \u043d\u0430\u0434 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/p>\n<p>  \u042f \u0432\u044b\u0431\u0440\u0430\u043b \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 Game Boy \u043f\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c:<\/p>\n<ul>\n<li>\u041e\u043d \u0438\u043c\u0435\u0435\u0442 \u0447\u0451\u0442\u043a\u0438\u0435 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043d\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u0443\u043c\u0430\u0442\u044c \u043d\u0430\u0434 \u0442\u0435\u043c, \u0447\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c.<\/li>\n<li>\u041e\u043d \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u0435\u043d, \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0437\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043d\u0435\u0439 \u0438\u043b\u0438 \u043d\u0435\u0434\u0435\u043b\u044c.<\/li>\n<li>\u041e\u043d \u043d\u0435 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0436\u0435\u043d, \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432.<\/li>\n<li>\u0423 \u043c\u0435\u043d\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0441\u044c \u0442\u0451\u043f\u043b\u044b\u0435 \u0432\u043e\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 \u0434\u0435\u0442\u0441\u0442\u0432\u0435 \u044f \u0438\u0433\u0440\u0430\u043b \u043d\u0430 Game Boy.<\/li>\n<\/ul>\n<p>  \u042f \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u0435\u0440\u0435\u0434 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c:<\/p>\n<ul>\n<li>\u041f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0441 \u0443\u043f\u043e\u0440\u043e\u043c \u043d\u0430 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u044c \u0438 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438.<\/li>\n<li>\u041a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 JavaScript \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <a href=\"https:\/\/github.com\/ocsigen\/js_of_ocaml\" rel=\"nofollow noopener noreferrer\">js_of_ocaml<\/a> \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435.<\/li>\n<li>\u0414\u043e\u0441\u0442\u0438\u0447\u044c \u0438\u0433\u0440\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f FPS \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043d\u0430 \u0441\u043c\u0430\u0440\u0442\u0444\u043e\u043d\u0435.<\/li>\n<li>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u043e\u0432 \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0431\u044d\u043a\u0435\u043d\u0434\u044b \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u043e\u0432. [\u042d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u044b \u2014 \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432\/\u0441\u0440\u0435\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/github.com\/mame\/optcarrot\" rel=\"nofollow noopener noreferrer\">\u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 NES<\/a> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043c\u0438\u0440\u0435 Ruby \u0434\u043b\u044f \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0438\u043d\u0433\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0440\u0435\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f Ruby, \u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 Chrome, \u043f\u043e\u0445\u043e\u0436\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430 <a href=\"https:\/\/github.com\/chromium\/octane\/blob\/master\/gbemu-part1.js\" rel=\"nofollow noopener noreferrer\">\u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 Game Boy<\/a> \u0434\u043b\u044f \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0438\u043d\u0433\u0430 \u0441\u0432\u043e\u0435\u0433\u043e \u0434\u0432\u0438\u0436\u043a\u0430 JS.]<\/li>\n<\/ul>\n<p>  <\/p>\n<h2>\u0426\u0435\u043b\u044c \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438<\/h2>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 Game Boy \u043d\u0430 OCaml.<\/p>\n<p>  \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430, \u0435\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435:<\/p>\n<ul>\n<li>\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 Game Boy.<\/li>\n<li>\u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043d\u0430 OCaml.<\/li>\n<li>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 OCaml.<\/li>\n<\/ul>\n<p>  \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0442\u0435\u043c\u044b:<\/p>\n<ul>\n<li>\u041a\u0440\u0430\u0442\u043a\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b Game Boy.<\/li>\n<li>\u041a\u0430\u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043a\u043e\u0434, \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d\u043e.<\/li>\n<li>\u041a\u0430\u043a \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u044b, GADT \u0438 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438.<\/li>\n<li>\u041a\u0430\u043a \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u0443\u0437\u043a\u0438\u0435 \u043c\u0435\u0441\u0442\u0430 \u0438 \u043f\u043e\u0432\u044b\u0448\u0430\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/li>\n<li>\u041e\u0431\u0449\u0438\u0435 \u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u044f \u043e\u0431 OCaml.<\/li>\n<\/ul>\n<p>  \u041c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0442\u0435\u043c\u044b:<\/p>\n<ul>\n<li>\u041e\u0441\u043d\u043e\u0432\u044b \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 OCaml<\/li>\n<li>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b Game Boy<\/li>\n<\/ul>\n<p>  \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u044d\u0442\u0438\u043c \u0442\u0435\u043c\u0430\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b\u00bb.<\/p>\n<h1>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h1>\n<p>  <\/p>\n<h2>\u0421\u0445\u0435\u043c\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/h2>\n<p>  \u0421\u0445\u0435\u043c\u0430\u0442\u0438\u0447\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 CAMLBOY \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c [\u0423\u0447\u0442\u0438\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u0445\u0435\u043c\u0430 \u043c\u043e\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u041d\u0415 \u0441\u0445\u0435\u043c\u0430 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044f Game Boy. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u044f \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043b \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a APU (Audio Processing Unit).]:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/714\/6b9\/0a2\/7146b90a2e75ca2cd236e500b304ac78.png\"\/><\/div>\n<p>  \u042f \u0431\u0443\u0434\u0443 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043f\u043e \u043c\u0435\u0440\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0430 \u0432\u043a\u0440\u0430\u0442\u0446\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0442\u0430\u043a:<\/p>\n<ul>\n<li>\u0426\u041f\/\u0442\u0430\u0439\u043c\u0435\u0440\/GPU \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u0442\u0430\u043a\u0442\u043e\u0432\u044b\u043c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u043c.<\/li>\n<li>\u0428\u0438\u043d\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u0426\u041f \u0438 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438, \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0438\u0440\u0443\u044f \u0447\u0442\u0435\u043d\u0438\u0435\/\u0437\u0430\u043f\u0438\u0441\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>0xFFFF<\/code> \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u0439 \u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442\/\u043e\u0442\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/li>\n<li>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0435 \u043a \u0448\u0438\u043d\u0435 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>Addressable_intf.S<\/code> (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044e \u043d\u0438\u0436\u0435)<\/li>\n<li>\u0428\u0438\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>Word_addressable_intf.S<\/code> (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044e \u043d\u0438\u0436\u0435)<\/li>\n<li>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0435\u0439.<\/li>\n<li>\u0422\u0430\u0439\u043c\u0435\u0440, GPU, \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0440\u0442 \u0438 \u0434\u0436\u043e\u0439\u0441\u0442\u0438\u043a \u043c\u043e\u0433\u0443\u0442 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u044f. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u0439 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u0442 \u043e \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d\u043d\u043e\u043c \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u0438 \u0426\u041f (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u0439 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442).<\/li>\n<\/ul>\n<p>  <\/p>\n<h2>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0438\u043a\u043b<\/h2>\n<p>  \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0438\u043a\u043b \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0442\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 (\u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043a\u0440\u0430\u0441\u043d\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c) \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/206\/159\/cb8\/206159cb84130013394c0e7902b78e8e.png\"\/><\/div>\n<p>  \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0438 \u0426\u041f\/\u0442\u0430\u0439\u043c\u0435\u0440\/GPU \u0438\u043c\u0435\u044e\u0442 \u043e\u0434\u0438\u043d \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u044b\u0439 \u0442\u0430\u043a\u0442\u043e\u0432\u044b\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043d\u0435\u0433\u043e, \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u2014 \u044d\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0446\u0438\u043a\u043b \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u043e\u0441\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u044d\u0442\u0438\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u0442\u0430\u043f\u044b:<\/p>\n<ol>\n<li>\u0426\u041f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0434\u043d\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0451\u043d\u043d\u044b\u0445 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u044d\u0442\u043e\u0433\u043e \u0442\u0430\u043a\u0442\u043e\u0432.<\/li>\n<li>\u0422\u0430\u0439\u043c\u0435\u0440 \u043f\u0440\u043e\u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044f \u0432\u043f\u0435\u0440\u0451\u0434 \u043d\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u043a\u0442\u043e\u0432, \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0451\u043d\u043d\u044b\u0445 \u0426\u041f.<\/li>\n<li>\u041f\u0440\u043e\u0434\u0432\u0438\u0433\u0430\u0435\u043c \u0432\u043f\u0435\u0440\u0451\u0434 GPU \u043d\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u043a\u0442\u043e\u0432, \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0451\u043d\u043d\u044b\u0445 \u0426\u041f.<\/li>\n<\/ol>\n<p>  \u0418\u043d\u043e\u0433\u0434\u0430 \u0442\u0430\u043a\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 <em>catch up method<\/em>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d\u0430 \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0430\u0439\u043c\u0435\u0440 \u0438 GPU \u00ab\u0434\u043e\u0433\u043e\u043d\u044f\u0442\u044c\u00bb \u0426\u041f. \u0412\u043e\u0442 \u0435\u0451 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/p>\n<pre><code class=\"delphi\">(* camlboy.ml *) let run_instruction t =   let mcycles = Cpu.run_instruction t.cpu in   Timer.run t.timer ~mcycles;   Gpu.run t.gpu ~mcycles<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f\/\u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<p>  \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0435.<\/p>\n<h3>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f\/\u0437\u0430\u043f\u0438\u0441\u0438 8-\u0431\u0438\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445<\/h3>\n<p>  \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f\/\u0437\u0430\u043f\u0438\u0441\u0438 8-\u0431\u0438\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u0440\u0438\u0441\u0443\u043d\u043a\u0435 \u043d\u0438\u0436\u0435 \u043a\u0440\u0430\u0441\u043d\u044b\u043c\u0438 \u043b\u0438\u043d\u0438\u044f\u043c\u0438.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/fd6\/eeb\/3cf\/fd6eeb3cfd709d5bb5c2606ca14fbd47.png\"\/><\/div>\n<p>  \u0428\u0438\u043d\u0430 (Bus) \u043c\u043e\u0436\u0435\u0442 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c 8-\u0431\u0438\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, GPU \u0438 RAM. \u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043c\u043e\u0434\u0443\u043b\u0435\u0439, \u0443\u043c\u0435\u044e\u0449\u0438\u0445 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c 8-\u0431\u0438\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u0442\u043e \u043d\u0430\u043c \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0438\u0445 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432 \u0447\u0451\u043c-\u0442\u043e \u0431\u044b\u043b \u043e\u0431\u0449\u0438\u043c.<\/p>\n<p>  \u0412 \u041e\u041e\u041f \u043c\u044b \u043c\u043e\u0436\u0435\u043c:<\/p>\n<ol>\n<li>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 (<code>public interface A {...}<\/code> \u0432 Java).<\/li>\n<li>\u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e (<code>implements A<\/code> \u0432 Java).<\/li>\n<\/ol>\n<p>  \u0412 OCaml \u043c\u044b \u043c\u043e\u0436\u0435\u043c:<\/p>\n<ol>\n<li>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 (<code>module type S = sig ... end<\/code>).<\/li>\n<li>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0435\u0451 (<code>include S with type t := t <\/code>).<\/li>\n<\/ol>\n<p>  \u0412 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u044d\u0442\u0438\u043c\u0438 \u0448\u0430\u0433\u0430\u043c\u0438 \u043c\u044b \u0437\u0430\u0434\u0430\u0451\u043c \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 <code>Addressable_intf.S<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c [<code>uint8<\/code> \u0438 <code>uint16<\/code> \u0432 \u043a\u043e\u0434\u0435 \u2014 \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0442\u0438\u043f\u044b OCaml, \u0430 \u0442\u0438\u043f\u044b \u0438\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f unsigned int (<code>units.mli<\/code>, <code>units.ml<\/code>).]:<\/p>\n<pre><code class=\"delphi\">(* addressable_intf.mli *) module type S = sig   type t   (* reads 8-bit data from address addr *)   val read_byte : t -> uint16 -> uint8   (* writes 8-bit data to address addr *)   val write_byte : t -> addr:uint16 -> data:uint8 -> unit   (* returns true if it accepts reads\/writes from addr and returns false if it can not *)   val accepts : t -> uint16 -> bool end<\/code><\/pre>\n<p>  \u0417\u0430\u0442\u0435\u043c \u043c\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c <code>Addressable_intf.S<\/code> \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u043c\u043e\u0434\u0443\u043b\u0435\u0439, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044e\u0449\u0438\u0445 8-\u0431\u0438\u0442\u043d\u044b\u0435 \u0447\u0442\u0435\u043d\u0438\u0435\/\u0437\u0430\u043f\u0438\u0441\u044c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0444\u0430\u0439\u043b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043c\u043e\u0434\u0443\u043b\u044f RAM <code>ram.mli<\/code> \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"delphi\">(* ram.mli *) type t ... include Addressable_intf.S with type t := t<\/code><\/pre>\n<p>  \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e <code>Addressable_intf.S<\/code> \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442 <code>gpu.mli<\/code>, <code>joypad.mli<\/code>, <code>timer.mli<\/code> \u0438 \u0442. \u043f.<\/p>\n<p>  <strong>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/strong><\/p>\n<p>  \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c <code>with type t := t<\/code> \u0432 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u043c \u0432\u044b\u0448\u0435 \u043a\u043e\u0434\u0435. \u0412 \u0446\u0435\u043b\u043e\u043c, <code>A with type t := s<\/code> \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 <code>t<\/code> \u0432 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0435 <code>A<\/code> \u043d\u0430 <code>s<\/code>. \u0422\u043e \u0435\u0441\u0442\u044c <code>include Addressable_intfS with type t := t<\/code> \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442:<\/p>\n<p>  <em>\u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0442\u0438\u043f <code>t<\/code> \u0432 <code>Addressable_intfS<\/code> \u043d\u0430 \u0442\u0438\u043f <code>t<\/code> \u0432 <code>Ram<\/code>, \u0430 \u0437\u0430\u0442\u0435\u043c <code>include<\/code> (\u00ab\u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c\u00bb \u0435\u0433\u043e \u0437\u0434\u0435\u0441\u044c)<\/em>.<\/p>\n<p>  \u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u0432\u044b\u0448\u0435\u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 <code>ram.mli<\/code> \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443:<\/p>\n<pre><code class=\"delphi\">(* ram.mli *) type t ... (* include Addressable_intf.S with type t := t will be \"expanded\" as the following *) val read_byte : t -> uint16 -> uint8 val write_byte : t -> addr:uint16 -> data:uint8 -> unit val accepts : t -> uint16 -> bool<\/code><\/pre>\n<p>  <\/p>\n<h3>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f\/\u0437\u0430\u043f\u0438\u0441\u0438 16-\u0431\u0438\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445<\/h3>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0447\u0442\u0435\u043d\u0438\u044f\/\u0437\u0430\u043f\u0438\u0441\u0438 16-\u0431\u0438\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u0441\u0445\u0435\u043c\u0435 \u043d\u0438\u0436\u0435 \u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u043b\u0438\u043d\u0438\u0435\u0439.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/d77\/980\/4ff\/d779804fff677f64ea0b55966f08287e.png\"\/><\/div>\n<p>  \u041c\u0435\u0436\u0434\u0443 \u0426\u041f \u0438 \u0448\u0438\u043d\u043e\u0439 \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a 8-\u0431\u0438\u0442\u043d\u044b\u043c \u0434\u0430\u043d\u043d\u044b\u043c \u043c\u043e\u0433\u0443\u0442 \u0442\u0430\u043a\u0436\u0435 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f\/\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f 16-\u0431\u0438\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0427\u0442\u043e\u0431\u044b \u0432\u044b\u0440\u0430\u0437\u0438\u0442\u044c \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u0435\u0441\u043b\u0438 \u0431\u044b \u043c\u044b \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u043e\u0433\u043b\u0438 \u00ab\u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c\u00bb \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f\/\u0437\u0430\u043f\u0438\u0441\u0438 8-\u0431\u0438\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 (<code>Addressable_intf.S<\/code>) \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0447\u0442\u0435\u043d\u0438\u044f\/\u0437\u0430\u043f\u0438\u0441\u0438 16-\u0431\u0438\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  \u0412 OOP \u043c\u044b \u043c\u043e\u0436\u0435\u043c<\/p>\n<ol>\n<li>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (<code>extends A<\/code> \u0432 Java).<\/li>\n<\/ol>\n<p>  \u0412 OCaml \u043c\u044b \u043c\u043e\u0436\u0435\u043c<\/p>\n<ol>\n<li>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 (<code>include A with type t := t <\/code>).<\/li>\n<\/ol>\n<p>  \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c <code>Addressable_intf.S<\/code> 16-\u0431\u0438\u0442\u043d\u044b\u043c \u0447\u0442\u0435\u043d\u0438\u0435\u043c\/\u0437\u0430\u043f\u0438\u0441\u044c\u044e, \u043c\u044b \u043c\u043e\u0436\u0435\u043c<\/p>\n<ol>\n<li>\u0417\u0430\u0434\u0430\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 <code>Word_addressable_intf.S<\/code>.<\/li>\n<li>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c <code>Addressable_intf.S<\/code><\/li>\n<li>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 (<code>read_word<\/code> \u0438 <code>write_word<\/code>)<\/li>\n<\/ol>\n<p>  \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"delphi\">(* word_addressable_intf.ml *) (** Interface that provide 16-bit read\/write in addition to 8-bit read\/write *) module type S = sig   type t   include Addressable_intf.S with type t := t   (* 16-bit reads\/writes *)   val read_word : t -> uint16 -> uint16   val write_word : t -> addr:uint16 -> data:uint16 -> unit end<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0428\u0438\u043d\u0430<\/h2>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0448\u0438\u043d\u044b, \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u043d\u0430 \u0441\u0445\u0435\u043c\u0435 \u043d\u0438\u0436\u0435 \u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u0440\u0430\u043c\u043a\u043e\u0439.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/063\/866\/532\/063866532a9ff97d2f114b0c435f867d.png\"\/><\/div>\n<p>  \u0428\u0438\u043d\u0430 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u0426\u041f \u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438 \u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0447\u0442\u0435\u043d\u0438\u044f\/\u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0448\u0438\u043d\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0447\u0442\u0435\u043d\u0438\u0435\/\u0437\u0430\u043f\u0438\u0441\u044c \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>0xC000<\/code> \u0432 RAM. \u041f\u043e\u043b\u043d\u0443\u044e \u0441\u0445\u0435\u043c\u0443 \u043f\u0430\u043c\u044f\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/gbdev.io\/pandocs\/Memory_Map.html\" rel=\"nofollow noopener noreferrer\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  \u041f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0432\u044b\u0448\u0435 <code>Word_addressable_intf.S<\/code> \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043c\u043e\u0434\u0443\u043b\u044f \u0448\u0438\u043d\u044b (<code>bus.mli<\/code>) \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<pre><code class=\"delphi\">(* bus.mli *) type t val create :   gpu:Gpu.t ->   timer:Timer.t ->   wram:Ram.t ->   ... ->   t include Word_addressable_intf.S with type t := t<\/code><\/pre>\n<p>  \u0417\u0430\u0442\u0435\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0448\u0438\u043d\u0443 (<code>bus.ml<\/code>) \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0438\u0436\u0435:<\/p>\n<pre><code class=\"delphi\">(* bus.ml *) type t = {   gpu   : Gpu.t;   timer : Timer.t;   wram  : Ram.t;   ... }  (* takes the modules connected to the bus as its argument *) let create ~gpu ~timer ~wram ... = {   gpu;   timer;   wram;   ... }  let read_byte t addr =   (* routes the data read to the appropriate module based on the given address *)   match addr with   | _ when Gpu.accepts t.gpu addr ->     Gpu.read_byte t.gpu addr   | _ when Timer.accepts t.timer addr ->     Timer.read_byte t.timer addr   | _ when Ram.accepts t.wram addr ->     Ram.read_byte t.wram addr   | ...  let read_word t addr =   (* The read_word function archives 16-bit reads by calling read_byte twice.      The actual hardware also achieves 16-bit read\/write by conducting 8-bit read\/write twice. *)   let lo = Uint8.to_int (read_byte t addr) in   let hi = Uint8.to_int (read_byte t Uint16.(succ addr)) in   (hi lsl 8) + lo |> Uint16.of_int<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u044b<\/h2>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432, \u043d\u0430 \u0441\u0445\u0435\u043c\u0435 \u043d\u0438\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u0440\u0430\u043c\u043a\u043e\u0439.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/6e1\/29c\/be3\/6e129cbe394b456a447c945428887bf3.png\"\/><\/div>\n<p>  \u0412 \u0426\u041f \u043a\u043e\u043d\u0441\u043e\u043b\u0438 Game Boy \u0435\u0441\u0442\u044c \u0432\u043e\u0441\u0435\u043c\u044c 8-\u0431\u0438\u0442\u043d\u044b\u0445 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432, <code>A<\/code>, <code>B<\/code>, <code>C<\/code>, <code>D<\/code>, <code>E<\/code>, <code>F<\/code>, <code>H<\/code> \u0438 <code>L<\/code>. \u042d\u0442\u0438 8-\u0431\u0438\u0442\u043d\u044b\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b \u043c\u043e\u0436\u043d\u043e \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 16-\u0431\u0438\u0442\u043d\u044b\u0445 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432 <code>AF<\/code>, <code>BC<\/code>, <code>DE<\/code> \u0438 <code>HL<\/code>. \u041d\u0438\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043c\u043e\u0434\u0443\u043b\u044f <code>Registers<\/code> (\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u043f\u0443\u0449\u0435\u043d\u0430):<\/p>\n<pre><code class=\"delphi\">(* registers.mli *)  type t (* identifiers of the 8-bit registers *) type r = A | B | C | D | E | F | H | L (* identifiers for the 16-bit registers *) type rr = AF | BC | DE | HL  ...  (* read\/write functions for the above registers *) val read_r   : t ->  r -> uint8 val write_r  : t ->  r -> uint8 -> unit val read_rr  : t -> rr -> uint16 val write_rr : t -> rr -> uint16 -> unit<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0426\u041f<\/h2>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0426\u041f, \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u043d\u0430 \u0441\u0445\u0435\u043c\u0435 \u043d\u0438\u0436\u0435 \u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u0440\u0430\u043c\u043a\u043e\u0439.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/375\/d8d\/d9c\/375d8dd9c70e2895b32b7372953f83a6.png\"\/><\/div>\n<p>  <\/p>\n<h3>\u041c\u043e\u044f \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0426\u041f<\/h3>\n<p>  \u041d\u0438\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430 \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0426\u041f. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>execute<\/code> \u0437\u0434\u0435\u0441\u044c \u043e\u043f\u0443\u0449\u0435\u043d\u044b, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u043d\u0438\u0445, \u043a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434.<\/p>\n<pre><code class=\"delphi\">(* cpu.mli *) type t val create : bus:Bus.t -> registers:Registers.t -> ... -> t val run_instruction : t -> int (* returns the # of cycles consumed *)<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"delphi\">(* cpu.ml *) type t = {   registers  : Registers.t;   bus        : Bus.t;   mutable pc : uint16; (* Program counter *)   ... }  (* Initializes the CPU by passing it's dependencies *) let create ~bus ~registers ... = {     bus;     registers;     ... }  (* Omitted for now. *) let execute t inst = ...  (* Fetches, decodes, and executes an instruction *) let run_instruction t =   ...   let inst = Fetch_and_decode.f t.bus ~pc:t.pc in   execute t inst<\/code><\/pre>\n<p>  <\/p>\n<h3>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0426\u041f<\/h3>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u0430\u044f \u0432\u044b\u0448\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0426\u041f \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u043e\u0434\u043d\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u2014 \u0435\u0451 \u0441\u043b\u043e\u0436\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u042d\u0442\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u0438\u0437 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u043d\u0438\u0436\u0435 \u0441\u0445\u0435\u043c\u044b:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/68d\/e84\/a9f\/68de84a9fffb1053dcde941764f919bb.png\"\/><\/div>\n<p>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0448\u0438\u043d\u0430 \u0438\u043c\u0435\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043e\u0442 \u0440\u0430\u0437\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439. \u042d\u0442\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u044e\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0426\u041f \u0432 \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u0430\u0445. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0426\u041f, \u043f\u043e\u043a\u0430 \u043c\u044b \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0448\u0438\u043d\u0443 \u0438 \u0432\u0441\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u043d\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0437\u0434\u043d\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0426\u041f \u0431\u044b\u043b \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u043c, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0448\u0438\u043d\u044b \u043e\u0442 \u0426\u041f. \u0421\u0434\u0435\u043b\u0430\u0432 \u044d\u0442\u043e, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0448\u0438\u043d\u0443 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u043e\u0439, \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0438\u0436\u0435:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/e2c\/a1f\/dcf\/e2ca1fdcf5e3cc0288e16576ec3cd326.png\"\/><\/div>\n<p>  \u0412 OCaml \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <em><strong>\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u0432<\/strong><\/em>.<\/p>\n<h3>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438<\/h3>\n<p>  \u042f \u0437\u0430\u043d\u043e\u0432\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u0426\u041f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u0432:<\/p>\n<pre><code class=\"delphi\">(* cpu.mli *)  (* We can now \"inject\" different implementations of the Bus via this functor argument *) module Make (Bus : Word_addressable_intf.S) : sig   type t   ... end<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"delphi\">(* cpu.ml *)  module Make (Bus : Word_addressable_intf.S) = struct   type t = {     registers  : Registers.t;     bus        : Bus.t;     mutable pc : uint16; (* Program counter *)     ...   }   ... end<\/code><\/pre>\n<p>  \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u0438\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0448\u0438\u043d\u044b \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0426\u041f \u0432 \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u0430\u0445:<\/p>\n<pre><code class=\"delphi\">(* test_cpu.ml *) ... (* Mock_bus is a simple implementation of `Word_addressable_intf.S`    which is implemented using a single byte array. *) module Cpu = Cpu.Make(Mock_bus) let cpu = Cpu.create ~bus:(Mock_bus.create ~size:0xFF) ... ...<\/code><\/pre>\n<p>  <\/p>\n<h2>\u041d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434<\/h2>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434 Game Boy \u043d\u0430 OCaml.<\/p>\n<p>  \u041d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434 Game Boy \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437<\/p>\n<ul>\n<li><em>8-\u0431\u0438\u0442\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434<\/em>: \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 8-\u0431\u0438\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (8-\u0431\u0438\u0442\u043d\u044b\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b, 8-\u0431\u0438\u0442\u043d\u044b\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0438 \u0442. \u043f.).<\/li>\n<li><em>16-\u0431\u0438\u0442\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434<\/em>: \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 16-\u0431\u0438\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (16-\u0431\u0438\u0442\u043d\u044b\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b, 16-\u0431\u0438\u0442\u043d\u044b\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0438 \u0442. \u043f.).<\/li>\n<\/ul>\n<p>  \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u043d\u0438\u0436\u0435:<\/p>\n<pre><code class=\"delphi\"># 8-bit version # Adds the 8-bit `A` register and `0x12`, then stores the result in the `A` register ADD8 A, 0x12 # 16-bit version # adds the 16-bit `AF` register and `0x1234`, then stores the result in the `AF` register ADD16 AF, 0x1234<\/code><\/pre>\n<p>  \u041a\u0430\u043a \u0436\u0435 \u043d\u0430\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434 \u043d\u0430 OCaml?<\/p>\n<h3>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432<\/h3>\n<p>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0435\u0440\u0432\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043b \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438 \u0438\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0432 \u0432\u0438\u0434\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432, \u043a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0438\u0436\u0435:<\/p>\n<pre><code class=\"django\">(* instruction.ml *)  (* Instruction arguments definied using variants *) type arg =   | Immediate8  of uint8   (*  8-bit value *)   | Immediate16 of uint16 (* 16-bit value *)   | R           of Registers.r      (*  8-bit register *)   | RR          of Registers.rr    (* 16-bit register *)   | ...  (* Instructions *) type t =   | ADD8  of arg * arg (*  8-bit version of ADD *)   | ADD16 of arg * arg (* 16-bit version of ADD *)   | ...<\/code><\/pre>\n<p>  \u041d\u043e \u0432\u0441\u043a\u043e\u0440\u0435 \u0437\u0430\u043c\u0435\u0442\u0438\u043b, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<h3>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432<\/h3>\n<p>  \u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442? \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u00ab\u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u044c\u00bb \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>execute<\/code>:<\/p>\n<pre><code class=\"delphi\">(* cpu.ml *)  (* Takes a single instruction and executes it. *) let execute t (inst : Instruction.t) =   ...   let read_arg = function     (* fetch values stored in the given argument *)     | Immidiate8  x -> x     | Immediate16 x -> x     | R  r          -> Registers.read_r r     | RR rr         -> Registers.read_rr rr     | ...   in   match inst with   | Add8 (x, y) ->     (* Fetches the value stored in the arguments x and y adds them. *)     let sum = Uint8.add (read_arg x) (read_arg y) in     ...   | Add16 (x, y) ->     let sum = Uint16.add (read_arg x) (read_arg y) in     ...  let run_instruction t =   ...   let inst = Fetch_and_decode.f t.bus ~pc:t.pc in   execute t inst<\/code><\/pre>\n<p>  \u042f \u0438\u0437\u0432\u043b\u0451\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>read_arg<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c, \u0432 \u0447\u0451\u043c \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435\u043b\u044c\u0437\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u0422\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043c\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0441 \u043a\u0430\u043a\u0438\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u043c \u043e\u043d \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f, \u043e \u0447\u0451\u043c \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445.<\/p>\n<pre><code class=\"delphi\">  (* What is the type of the return value? *)   let read_arg : Instruction.arg -> ??? = function     ...     | R r  ->       (* fetches the value of 8-bit register. *)       (* returns uint8 in this case. *)       Registers.read_r r     | RR r ->       (* fetches the value of 16-bit register. *)       (* returns uint16 in this case. *)       Registers.read_rr r   in<\/code><\/pre>\n<p>  \u0412 \u044d\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u044f \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043b \u043e <em><strong>GADT<\/strong><\/em> (<em><strong>Generalized Algebraic Data Type<\/strong><\/em>) \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u044f\u0437\u044b\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u0438\u0437\u0443\u0447\u0430\u043b \u0440\u0430\u043d\u044c\u0448\u0435, \u043d\u043e \u0442\u0430\u043a \u0438 \u043d\u0435 \u043e\u0441\u0432\u043e\u0438\u043b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e.<\/p>\n<h3>\u041d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 GADT<\/h3>\n<p>  \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0437\u0430\u043d\u043e\u0432\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0439 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 GADT \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0442\u0438\u043f\u0430 <code>arg<\/code> \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432.<\/p>\n<pre><code class=\"delphi\">(* instruction.ml *)  (* Instruction arguments definied using GADTs *) type _ arg =   | Immediate8  : uint8        -> uint8  arg   | Immediate16 : uint16       -> uint16 arg   | R           : Registers.r  -> uint8  arg   | RR          : Registers.rr -> uint16 arg   | ...  (* Instructions *) type t =   | ADD8  of uint8 arg * uint8 arg   | ADD16 of uint16 arg * uint16 arg   | ...<\/code><\/pre>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c \u0441\u043c\u044b\u0441\u043b \u044d\u0442\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u0440\u0435\u0442\u044c\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0442\u0438\u043f\u0430 <code>arg<\/code>:<\/p>\n<pre><code class=\"delphi\">  | R : Registers.r -> uint8  arg<\/code><\/pre>\n<p>  \u0422\u0438\u043f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 (<code>Registers.r<\/code> \u0432 <code>Registers.r -> uint8 arg<\/code>) \u0438\u043c\u0435\u0435\u0442 \u0442\u0443 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0447\u0442\u043e \u0438 <code>of Registers.r<\/code> \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432. \u041e\u043d \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 <strong>\u0442\u0438\u043f <em>\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u043e\u0433\u043e<\/em> \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430<\/strong>.<\/p>\n<p>  \u0412 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u043d\u0438\u0436\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0442\u0438\u043f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0439 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f (\u0442\u0438\u043f <code>r<\/code> \u0438 <code>rr<\/code>) \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430. \u042d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0438\u043f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"delphi\">let read_arg = function   ...   | R   r -> .. (* type of r is Registers.r *)   | RR rr -> .. (* type of rr is Registers.rr *)   ...<\/code><\/pre>\n<p>  \u0422\u043e\u0433\u0434\u0430 \u0447\u0442\u043e \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 (<code>uint8 arg<\/code> in <code>Registers.r -> uint8 arg<\/code>)? \u041f\u043e\u0445\u043e\u0436\u0435, \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0435\u043c\u0443 \u043d\u0438\u0447\u0442\u043e \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043e\u043d \u043c\u0435\u043d\u044f\u0435\u0442 <strong>\u0442\u0438\u043f <i>\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e<\/i> \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430<\/strong>.<\/p>\n<p>  \u0412\u0437\u0433\u043b\u044f\u043d\u0438\u0442\u0435 \u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u0443\u044e \u043d\u0438\u0436\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0442\u0438\u043f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430. \u042d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"delphi\">let read_arg = function   ..   | R   r -> Registers.read_r r   (* returns uint8 *)   | RR rr -> Registers.read_rr rr (* returns uint16 *)   ...<\/code><\/pre>\n<p>  \u041f\u043e\u0434\u0432\u0435\u0434\u0451\u043c \u0438\u0442\u043e\u0433: <strong>\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0438\u043f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0445 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/strong>, \u0430 <strong>GATD \u043c\u043e\u0433\u0443\u0442 \u0442\u0430\u043a\u0436\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0438\u043f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/strong>. \u0412 \u044d\u0442\u043e\u043c \u0441\u043c\u044b\u0441\u043b\u0435 GADT \u0431\u043e\u043b\u0435\u0435 \u00ab\u043e\u0431\u043e\u0431\u0449\u0435\u043d\u044b\u00bb, \u0447\u0435\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b; \u043d\u0430\u0432\u0435\u0440\u043d\u043e, \u043e\u0442\u0441\u044e\u0434\u0430 \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u201cGeneralized\u201d Algebraic Data Type.<\/p>\n<p>  \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043d\u043e\u0432\u043e\u043c\u0443 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u043c\u0443 <code>Instruction.arg<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f GADT, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e <code>execute<\/code>. \u0422\u0438\u043f <code>'a Instruction.arg -> 'a<\/code> \u0432 <code>read_arg<\/code> \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0438\u043f\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430.<\/p>\n<pre><code class=\"delphi\">let execute t (inst : Instruction.t) =   ...   let read_arg : type a. a Instruction.arg -> a = fun arg ->     match arg with     | Immediate8  n -> n     | Immediate16 n -> n     | ...   in   match inst with   | Add8 (x, y) ->     let sum = Uint8.add (read_arg x) (read_arg y) in     ...   | Add16 (x, y) ->     let sum = Uint16.add (read_arg x) (read_arg y) in     ...<\/code><\/pre>\n<p>  \u0414\u043b\u044f \u0441\u043f\u0440\u0430\u0432\u043a\u0438 \u0432\u043e\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434, \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 GADT:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"delphi\">type _ arg =   | Immediate8  : uint8        -> uint8  arg   | Immediate16 : uint16       -> uint16 arg   | Direct8     : uint16       -> uint8  arg   | Direct16    : uint16       -> uint16 arg   | R           : Registers.r  -> uint8  arg   | RR          : Registers.rr -> uint16 arg   | RR_indirect : Registers.rr -> uint8  arg   | FF00_offset : uint8        -> uint8  arg   | FF00_C      : uint8 arg   | HL_inc      : uint8 arg   | HL_dec      : uint8 arg   | SP          : uint16 arg   | SP_offset   : int8         -> uint16 arg  type condition =   | None   | NZ   | Z   | NC   | C  type t =   | LD8   of uint8 arg * uint8 arg   | LD16  of uint16 arg * uint16 arg   | ADD8  of uint8 arg * uint8 arg   | ADD16 of uint16 arg * uint16 arg   | ADDSP of int8   | ADC   of uint8 arg * uint8 arg   | SUB   of uint8 arg * uint8 arg   | SBC   of uint8 arg * uint8 arg   | AND   of uint8 arg * uint8 arg   | OR    of uint8 arg * uint8 arg   | XOR   of uint8 arg * uint8 arg   | CP    of uint8 arg * uint8 arg   | INC   of uint8 arg   | INC16 of uint16 arg   | DEC   of uint8 arg   | DEC16 of uint16 arg   | SWAP  of uint8 arg   | DAA   | CPL   | CCF   | SCF   | NOP   | HALT   | STOP   | DI   | EI   | RLCA   | RLA   | RRCA   | RRA   | RLC   of uint8 arg   | RL    of uint8 arg   | RRC   of uint8 arg   | RR    of uint8 arg   | SLA   of uint8 arg   | SRA   of uint8 arg   | SRL   of uint8 arg   | BIT   of int * uint8 arg   | SET   of int * uint8 arg   | RES   of int * uint8 arg   | PUSH  of Registers.rr   | POP   of Registers.rr   | JP    of condition * uint16 arg   | JR    of condition * int8   | CALL  of condition * uint16   | RST   of uint16   | RET   of condition   | RETI<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<h2>\u041a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0438<\/h2>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0435\u0439, \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u043d\u0430 \u0441\u0445\u0435\u043c\u0435 \u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u0440\u0430\u043c\u043a\u043e\u0439.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/f19\/d41\/4df\/f19d414df75cd2296c52fd5703229e99.png\"\/><\/div>\n<p>  \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0443\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0438 \u0434\u043b\u044f Game Boy \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e ROM (\u043f\u0430\u043c\u044f\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f), \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435\/\u043a\u043e\u0434 \u0438\u0433\u0440\u044b, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a. \u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430\u0445 \u0434\u043b\u044f Game Boy \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u044e\u0449\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c Game Boy. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430\u0445 \u0442\u0438\u043f\u0430 ROM_ONLY (\u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, Tetris) \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e ROM, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435\/\u043a\u043e\u0434 \u0438\u0433\u0440\u044b, \u0430 \u0432 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430\u0445 \u0442\u0438\u043f\u0430 MBC3 (\u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, Pok\u00e9mon Red) \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a ROM \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u0430\u044f RAM \u0438 \u0442\u0430\u0439\u043c\u0435\u0440\u044b.<\/p>\n<p>  \u0422\u0430\u043a \u043a\u0430\u043a \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436 \u0438\u043c\u0435\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0438\u043f \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430 \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438. \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u043c\u043e\u0434\u0443\u043b\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0442\u0438\u043f\u0443 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430.<\/p>\n<p>  \u0414\u043b\u044f \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u00ab\u0432\u044b\u0431\u043e\u0440\u0430 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f\u00bb \u043f\u043e\u043b\u0435\u0437\u043d\u044b <strong><em>\u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438<\/em><\/strong> (first-class modules). \u041a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0438\u0436\u0435, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c <code>Detect_cartridge.f<\/code>, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0443\u044e \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u0438\u043f\u0430 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430. \u0412 \u043f\u043e\u0441\u0442\u0435 \u043c\u044b \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u043c \u0435\u0451 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<pre><code class=\"delphi\">(* detect_cartridge.mli *) val f : rom_bytes:Bigstringaf.t -> (module Cartridge_intf.S)<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h2>\n<p>  \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 ROM \u0438 <code>ppx_expect<\/code> \u0434\u043b\u044f \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u0439 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 <em>\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/em>.<\/p>\n<h3>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 ROM<\/h3>\n<p>  \u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0435 ROM \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 ROM, \u043a\u043e\u0442\u043e\u0440\u044b\u0435:<\/p>\n<ul>\n<li>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442, \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0435 \u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/li>\n<li>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442, \u0430\u0434\u0435\u043a\u0432\u0430\u0442\u043d\u043e \u043b\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0438\u043f \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430 MBC1.<\/li>\n<\/ul>\n<p>  \u0422\u0430\u043a\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 ROM \u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u0432, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443, \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 ROM, \u043e\u043d\u0438<\/p>\n<ul>\n<li>\u0414\u0430\u044e\u0442 \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0430\u0441\u043f\u0435\u043a\u0442 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 \u0434\u0430\u0451\u0442 \u0441\u0431\u043e\u0439.<\/li>\n<li>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430.<\/li>\n<\/ul>\n<p>  \u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0435 ROM \u043e\u0431\u044b\u0447\u043d\u043e \u0432\u044b\u0432\u043e\u0434\u044f\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u0430 \u043d\u0430 \u0434\u0438\u0441\u043f\u043b\u0435\u0439 [\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 ROM, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/github.com\/retrio\/gb-test-roms\" rel=\"nofollow noopener noreferrer\">blargg test roms<\/a>, \u0432\u044b\u0432\u043e\u0434\u044f\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0440\u0442 \u0432 \u0432\u0438\u0434\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 ASCII. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0435\u0449\u0451 \u0434\u0430\u0436\u0435 \u0434\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 GPU.]. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0440\u0430\u0431\u043e\u0442\u044b <a href=\"https:\/\/github.com\/Gekkio\/mooneye-test-suite\" rel=\"nofollow noopener noreferrer\">mooneye test ROMs<\/a> \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0442\u0430\u043a, \u043a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u0445 \u043d\u0438\u0436\u0435. \u0422\u0435\u043a\u0441\u0442, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0439 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0431\u043e\u044f \u2014 \u044d\u0442\u043e \u0434\u0430\u043c\u043f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432 \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0441\u0431\u043e\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u0447\u043d\u043e\u0433\u043e \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/fb3\/a8e\/5c3\/fb3a8e5c341892ffe2ea6861b0dff375.png\"\/><\/div>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/435\/b2e\/34e\/435b2e34e95fa82bcf97c8da268b4112.png\"\/><\/div>\n<p>  <\/p>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432<\/h3>\n<p>  \u041d\u0438\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e ROM \u0438 <a href=\"https:\/\/github.com\/janestreet\/ppx_expect\" rel=\"nofollow noopener noreferrer\"><code>ppx_expect<\/code><\/a>. \u0412\u043e\u0442 \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442:<\/p>\n<ol>\n<li><code>M.run_test_rom_and_print_framebuffer<\/code> \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 ROM \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 ASCII.<\/li>\n<li>\u0412\u044b\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 <code>...<\/code> \u0432 <code>[%expect{|...|}]<\/code>.<\/li>\n<\/ol>\n<p>  \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043e <code>ppx_expect<\/code> \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432 <a href=\"https:\/\/blog.janestreet.com\/testing-with-expectations\" rel=\"nofollow noopener noreferrer\">\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a>.<\/p>\n<pre><code class=\"delphi\">let%expect_test \"bits_mode.gb\" =   M.run_test_rom_and_print_framebuffer \"mbc1\/bits_mode.gb\";    [%expect{|     008:-#######-----------------------------------###---#---#----------------------------------------------------------------------------------------------------------     009:----#-----####-----###-----#--------------#---#--#--#-----------------------------------------------------------------------------------------------------------     010:----#----#----#---#-------####------------#---#--#-#------------------------------------------------------------------------------------------------------------     011:----#----######----##------#--------------#---#--###------------------------------------------------------------------------------------------------------------     012:----#----#-----------#-----#--------------#---#--#--#-----------------------------------------------------------------------------------------------------------     013:----#-----####----###------##--------------###---#---#---------------------------------------------------------------------------------------------------------- |}]<\/code><\/pre>\n<p>  \u042d\u0442\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u0440\u0438\u0434\u0430\u043b\u0438 \u043c\u043d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438 \u0432\u043d\u0435\u0441\u0435\u043d\u0438\u0438 \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u043a\u043e\u0434, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u044f\u0432\u043b\u044f\u0442\u044c \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u0438.<\/p>\n<h3>\u0418\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>  \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u044d\u0442\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u0438 \u043c\u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0432 \u0441\u0442\u0438\u043b\u0435 <a href=\"https:\/\/blog.janestreet.com\/repeatable-exploratory-programming\/\" rel=\"nofollow noopener noreferrer\"><em>\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/em><\/a>. \u041a\u043e\u0433\u0434\u0430 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u044f<\/p>\n<ol>\n<li>\u041d\u0430\u0445\u043e\u0434\u0438\u043b \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 ROM, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0438\u0439 \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/li>\n<li>\u0421\u043e\u0437\u0434\u0430\u0432\u0430\u043b \u0442\u0435\u0441\u0442\u044b <code>ppx_expect<\/code>, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 ROM.<\/li>\n<li>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u043b \u0442\u0435\u0441\u0442\u044b \u0438 \u043a\u043e\u043c\u043c\u0438\u0442\u0438\u043b \u0432\u044b\u0432\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0441\u0431\u043e\u0435\u0432.<\/li>\n<li>\u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/li>\n<li>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u043b, \u043f\u0435\u0440\u0435\u0448\u0451\u043b \u043b\u0438 \u0442\u0435\u0441\u0442 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u00abTest OK\u00bb.<\/li>\n<\/ol>\n<p>  <\/p>\n<h2>\u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u0432 JavaScript<\/h2>\n<p>  \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u0432 JavaScript \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043d\u0430 \u0443\u0434\u0438\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f <a href=\"https:\/\/github.com\/ocsigen\/js_of_ocaml\" rel=\"nofollow noopener noreferrer\">js_of_ocaml<\/a>. \u041c\u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0432\u0441\u0435\u0433\u043e <a href=\"https:\/\/github.com\/linoscope\/CAMLBOY\/commit\/ac04c5d1ca39514cf7f34d19b2c5e702cc3d28c1\" rel=\"nofollow noopener noreferrer\">\u043e\u0434\u043d\u0438\u043c \u043a\u043e\u043c\u043c\u0438\u0442\u043e\u043c<\/a>.<\/p>\n<p>  \u041f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0433\u043e UI \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/dbuenzli\/brr\" rel=\"nofollow noopener noreferrer\">Brr<\/a>. \u0423\u0434\u043e\u0431\u0441\u0442\u0432\u043e Brr \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u043d\u0430 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u044b JS \u0441 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438 OCaml, \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0433\u043e API <code>js_of_ocaml<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u044b JS \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 OCaml, \u0442\u0440\u0435\u0431\u0443\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u043d\u0438\u0439 \u043e\u0431 \u00abO\u00bb \u0432 OCaml.<\/p>\n<h2>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>  \u0425\u043e\u0442\u044c \u043c\u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u2014 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0431\u044b\u043b \u043d\u0435\u0438\u0433\u0440\u0430\u0431\u0435\u043b\u044c\u043d\u043e \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u043c. \u041d\u0438\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u043a\u0430\u043a \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u043d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043d\u0430 PC, \u0440\u0430\u0431\u043e\u0442\u0430\u044f \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 20 FPS. \u0420\u0435\u0430\u043b\u044c\u043d\u044b\u0439 Game Boy \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 60 FPS, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u0442\u0440\u043e\u0435.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/e6e\/913\/415\/e6e9134152dd3b0c46a8ed2824e326ae.gif\"\/><\/div>\n<p>  \u0418 \u0442\u0430\u043a \u043d\u0430\u0447\u0430\u043b\u0441\u044f \u043c\u043e\u0439 \u043f\u0443\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<h3>\u041f\u043e\u0438\u0441\u043a \u0443\u0437\u043a\u0438\u0445 \u043c\u0435\u0441\u0442 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0430<\/h3>\n<p>  \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u043c Chrome \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0443\u0437\u043a\u0438\u0445 \u043c\u0435\u0441\u0442 [\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0430 Chrome \u0441\u0442\u0430\u043b\u0430 \u043f\u0440\u0438\u044f\u0442\u043d\u044b\u043c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u043c \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0432 JS.]. \u0412\u043e\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/c00\/b2b\/330\/c00b2b330567fcd45d5c16310ecb37d1.png\"\/><\/div>\n<p>  \u041d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0435 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e GPU \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 73% \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0430 <code>tile_data.ml<\/code>, <code>oam_table.ml<\/code> \u0438 <code>tile_map<\/code> \u0442\u0440\u0430\u0442\u044f\u0442, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e 34%, 18% \u0438 8% \u0432\u0440\u0435\u043c\u0435\u043d\u0438.<\/p>\n<p>  \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u044f \u0432\u044b\u044f\u0441\u043d\u0438\u043b, \u0447\u0442\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0442\u0440\u0430\u0442\u044f\u0442 <code>timer.ml<\/code> \u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>Bigstringaf<\/code>.<\/p>\n<h3>\u0423\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0443\u0437\u043a\u0438\u0445 \u043c\u0435\u0441\u0442<\/h3>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u044f \u0437\u043d\u0430\u043b, \u0433\u0434\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0443\u0437\u043a\u0438\u0435 \u043c\u0435\u0441\u0442\u0430, \u044f \u043d\u0430\u0447\u0430\u043b \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u0434 \u0438\u0445 \u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c. \u0422\u0430\u043a \u043a\u0430\u043a \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0435 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0442\u0435 \u0447\u0430\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u0441\u043d\u0443\u043b\u0438\u0441\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0438\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b.<\/p>\n<ul>\n<li>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d <code>oam_table.ml<\/code> (<a href=\"https:\/\/github.com\/linoscope\/CAMLBOY\/commit\/47989b77451873202268c955bc3b650420e648e8\" rel=\"nofollow noopener noreferrer\">\u043a\u043e\u043c\u043c\u0438\u0442<\/a>):<br \/> \n<ul>\n<li>14fps -> 24fps<\/li>\n<\/ul>\n<\/li>\n<li>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d <code>tile_data.ml<\/code> (<a href=\"https:\/\/github.com\/linoscope\/CAMLBOY\/commit\/bdc7c58c8ec1720eb38f59a64320d06f655f78f5\" rel=\"nofollow noopener noreferrer\">\u043a\u043e\u043c\u043c\u0438\u0442<\/a>):<br \/> \n<ul>\n<li>24fps -> 35fps<\/li>\n<\/ul>\n<\/li>\n<li>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d <code>timer.ml<\/code> (<a href=\"https:\/\/github.com\/linoscope\/CAMLBOY\/commit\/db49742096db50f1f52cb72b2e5136fbd4912163\" rel=\"nofollow noopener noreferrer\">\u043a\u043e\u043c\u043c\u0438\u0442<\/a>):<br \/> \n<ul>\n<li>35fps -> 40fps<\/li>\n<\/ul>\n<\/li>\n<li>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d <code>tile_map.ml<\/code> (<a href=\"https:\/\/github.com\/linoscope\/CAMLBOY\/commit\/7c2a6b9f694c57983da032d71a44f81f51e3cb65\" rel=\"nofollow noopener noreferrer\">\u043a\u043e\u043c\u043c\u0438\u0442<\/a>):\n<ul>\n<li>40fps -> 50fps<\/li>\n<\/ul>\n<\/li>\n<li>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 <code>Bigstringaf.unsafe_get<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>Bigstringaf.get<\/code> (<a href=\"https:\/\/github.com\/linoscope\/CAMLBOY\/commit\/2691a664465051eaa3b93954675e636ca4ec835a\" rel=\"nofollow noopener noreferrer\">\u043a\u043e\u043c\u043c\u0438\u0442<\/a>):<br \/> \n<ul>\n<li>50fps -> 60fps<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  <\/p>\n<h3>\u041e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043d\u0438\u044f<\/h3>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 60 FPS \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043d\u0430 \u043c\u043e\u0451\u043c PC, \u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0441 20-40 FPS \u043d\u0430 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435. \u042f \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e \u0432\u044b\u0432\u043e\u0434 JS \u0438\u0437 \u0440\u0435\u043b\u0438\u0437\u043d\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0438 \u0431\u044b\u043b \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435, \u0447\u0435\u043c \u0432\u044b\u0432\u043e\u0434 JS \u0438\u0437 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0438. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f <a href=\"https:\/\/discuss.ocaml.org\/t\/js-of-ocaml-output-performs-considerably-worse-when-built-with-profile-release-flag\/8862\" rel=\"nofollow noopener noreferrer\">\u043f\u043e\u043c\u043e\u0449\u0438<\/a> \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 discuss.ocaml.org \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043d\u0438\u0435 js_of_ocaml \u0437\u0430\u043c\u0435\u0434\u043b\u044f\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u0443 JS (\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u043b\u0438\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0430 \u0434\u0432\u0438\u0436\u043e\u043a JS \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 JIT-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044e, \u043a\u043e\u0433\u0434\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0434\u043b\u0438\u043d\u043d\u0430\u044f).<\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043d\u0438\u044f \u043c\u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0441\u0442\u0438\u0447\u044c 100 FPS \u043d\u0430 \u043c\u043e\u0451\u043c PC \u0438 60 FPS \u043d\u0430 \u043c\u043e\u0451\u043c \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435. \u041d\u0438\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430 gif \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0433\u043e \u0441 100 FPS \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043d\u0430 PC. (\u0414\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435: \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u043e\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 <a href=\"https:\/\/github.com\/ocsigen\/js_of_ocaml\/pull\/1220\" rel=\"nofollow noopener noreferrer\">ocsigen\/js_of_ocaml#1220<\/a>)<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/74d\/5f7\/1a8\/74d5f71a89756fd8be010062a7ee0b7d.gif\"\/><\/div>\n<p>  \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 JS \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0432\u044b\u0441\u0438\u043b\u0430 \u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u041d\u0438\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 1000 FPS \u0432 \u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0440\u0435\u0434\u0435.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/1fe\/b37\/313\/1feb3731343a3bc6d3e950d5c7c273bc.gif\"\/><\/div>\n<p>  <\/p>\n<h2>\u0411\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0438<\/h2>\n<p>  \u042f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b <em>\u0431\u0435\u0437\u0433\u043e\u043b\u043e\u0432\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0438\u043d\u0433\u0430<\/em> \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 \u0431\u0435\u0437 UI. \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043c\u0435\u0440\u0430 FPS \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0431\u044d\u043a\u0435\u043d\u0434\u0430\u0445 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u043e\u0432 OCaml \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u044b\u043b \u0442\u0430\u043a\u0438\u043c [\u041f\u043e\u043c\u043d\u0438\u0442\u0435, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f FPS \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430\u043c\u0438 Game Boy, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 \u0441\u0438\u043b\u044c\u043d\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u043d \u0442\u043e\u0447\u0435\u043d \u0438 \u043a\u0430\u043a\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438\u043c\u0435\u0435\u0442. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 CALMBOY \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d APU (Audio Processing Unit), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u0442 \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0441\u043c\u044b\u0441\u043b\u0430 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e FPS \u0441 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430\u043c\u0438, \u0438\u043c\u0435\u044e\u0449\u0438\u043c\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 APU.]:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/b50\/f28\/493\/b50f2849371f9cb52d5299fcba77bcfc.png\"\/><\/div>\n<p>  <\/p>\n<h1>\u0417\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u044b\u0432\u043e\u0434\u044b<\/h1>\n<p>  <\/p>\n<h2>\u0420\u0430\u0437\u043c\u044b\u0448\u043b\u0435\u043d\u0438\u044f \u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u0432<\/h2>\n<p>  \u041c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u0432 \u043f\u043e\u0445\u043e\u0436\u0430 \u043d\u0430 \u0441\u043e\u0440\u0435\u0432\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435. \u041e\u0431\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u0432 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f\u0445 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u044d\u0442\u0430\u043f\u043e\u0432:<\/p>\n<ul>\n<li>\u0427\u0442\u0435\u043d\u0438\u0435 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u2014 \u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0441\u043e\u0440\u0435\u0432\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0438 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0430\/\u0432\u0438\u043a\u0438-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u0432.<\/li>\n<li>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439.<\/li>\n<li>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u2014 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043e\u043d\u043b\u0430\u0439\u043d-\u0441\u0443\u0434\u044c\u0435 \u0432 \u0441\u043e\u0440\u0435\u0432\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 ROM \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u0432.<\/li>\n<\/ul>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u043c \u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u0441\u043e\u0440\u0435\u0432\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043b\u044e\u0434\u044f\u043c (\u0442\u0438\u043f\u0430 \u043c\u0435\u043d\u044f), \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u043c \u043a\u043e\u0434\u0438\u0442\u044c, \u043d\u043e \u0441 \u0442\u0440\u0443\u0434\u043e\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b\u0445 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c. \u0412 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u044f \u0431\u0443\u0434\u0443 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u0438\u043c \u043b\u044e\u0434\u044f\u043c \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u0432.<\/p>\n<h2>\u0427\u0442\u043e \u043c\u043d\u0435 \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u043e\u0441\u044c \u0432 OCaml<\/h2>\n<p>  <\/p>\n<h4>\u042d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430<\/h4>\n<p>  \u042d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430 OCaml \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u043b\u0430\u0441\u044c \u0441 \u0442\u0435\u0445 \u0432\u0440\u0435\u043c\u0451\u043d, \u043a\u043e\u0433\u0434\u0430 \u044f \u0441\u043e\u043f\u0440\u0438\u043a\u0430\u0441\u0430\u043b\u0441\u044f \u0441 OCaml (\u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0448\u0435\u0441\u0442\u044c \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434). \u0412\u043e\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b:<\/p>\n<ul>\n<li>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f <a href=\"https:\/\/dune.readthedocs.io\/en\/stable\/\" rel=\"nofollow noopener noreferrer\">dune<\/a> \u043c\u044b \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043a\u0438\u043d\u0443\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u0432 \u043f\u0430\u043f\u043a\u0443, \u0430 \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u0431\u043e\u0440\u043a\u0438, \u0447\u0442\u043e \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u0430\u0445 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043d\u043e\u0440\u043c\u043e\u0439.<\/li>\n<li>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u041f\u041e \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435 <a href=\"https:\/\/github.com\/ocaml\/merlin\" rel=\"nofollow noopener noreferrer\">Merlin<\/a> \u0438 <a href=\"https:\/\/github.com\/ocaml-ppx\/ocamlformat\" rel=\"nofollow noopener noreferrer\">OCamlformat<\/a> \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f, \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043f\u043e \u043a\u043e\u0434\u0443 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u043b\u043e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0435\u0441\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u043c.<\/li>\n<li>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f <a href=\"https:\/\/github.com\/ocaml\/setup-ocaml\" rel=\"nofollow noopener noreferrer\">setup-ocaml<\/a> \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0438 \u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c\u0438 Github \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u043a\u043e\u043c\u043c\u0438\u0442\u043e\u043c \u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430.<\/li>\n<\/ul>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 OCaml \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434, \u043d\u043e \u0437\u0430\u0431\u0440\u043e\u0441\u0438\u043b\u0438 \u0435\u0433\u043e \u0438\u0437-\u0437\u0430 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0442\u043e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0434\u0430\u0442\u044c \u0435\u043c\u0443 \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u0448\u0430\u043d\u0441.<\/p>\n<h4>\u0427\u0442\u043e\u0431\u044b \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c, \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u044b\u0442\u044c \u00ab\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c\u00bb<\/h4>\n<p>  \u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c \u044f\u0437\u044b\u043a\u043e\u043c \u0447\u0430\u0441\u0442\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u0442\u0430\u043a\u043e\u0439 \u044f\u0437\u044b\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u00ab\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0441\u0442\u0438\u043b\u044c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0438\u043c\u0435\u044e\u0449\u0438\u0439 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432\u00bb, \u043d\u043e \u043c\u0435\u043d\u044f \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0430\u043f\u0440\u044f\u0433\u0430\u043b\u043e \u044d\u0442\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u00ab\u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b\u00bb. \u042f \u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u044e, \u0447\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043e\u0447\u043d\u043e, \u043f\u0440\u043e\u0441\u0442\u043e \u044f \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u044e, \u0447\u0442\u043e \u0441\u0430\u043c\u0438 \u043f\u043e \u0441\u0435\u0431\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439. \u041e\u0442\u043a\u0440\u044b\u0442\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u2014 \u044d\u0442\u043e \u043f\u043b\u043e\u0445\u043e, \u043d\u043e \u0440\u0430\u0437\u0432\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043f\u0440\u044f\u0442\u0430\u0442\u044c \u0435\u0433\u043e \u0437\u0430 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0435\u0439?<\/p>\n<p>  \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435. \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 CAMLBOY \u043f\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0435\u0441\u0442\u044c \u043a\u0443\u0447\u0430 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. \u041c\u043d\u043e\u0433\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0438\u043c\u0435\u044e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441 \u0442\u0438\u043f\u043e\u043c <code>t -> ... -> unit<\/code>, \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0449\u0438\u043c \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u0418 \u0445\u043e\u0442\u044f \u044d\u0442\u043e \u00ab\u043d\u0435\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f\u00bb \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043c\u043d\u0435 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u044f \u0443\u043f\u0443\u0441\u043a\u0430\u044e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 OCaml.<\/p>\n<p>  \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u044f \u043b\u044e\u0431\u043b\u044e \u043d\u0435 \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u00ab\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435\u00bb \u044f\u0437\u044b\u043a\u0438, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044f\u0437\u044b\u043a\u0438 \u0441\u043e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c\u0438, \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432, \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0438 \u0445\u043e\u0440\u043e\u0448\u0438\u043c \u0432\u044b\u0432\u043e\u0434\u043e\u043c \u0442\u0438\u043f\u043e\u0432.<\/p>\n<h2>\u0427\u0442\u043e \u043c\u043d\u0435 \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0432 OCaml<\/h2>\n<p>  <\/p>\n<h4>\u042d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430<\/h4>\n<p>  \u0425\u043e\u0442\u044f \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u043b\u0430\u0441\u044c, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0449\u0438 \u043a\u0430\u0436\u0443\u0442\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438 \u0438\u043b\u0438 \u043f\u043b\u043e\u0445\u043e \u0437\u0430\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0443 \u043c\u0435\u043d\u044f \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u043b\u0438 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0438 \u0441 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u044b\u043c \u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432 <a href=\"https:\/\/opam.ocaml.org\/doc\/Usage.html\" rel=\"nofollow noopener noreferrer\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435 opam<\/a> \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0447\u0451\u0442\u043a\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434 \u044f \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 <a href=\"https:\/\/github.com\/ocaml\/setup-ocaml\" rel=\"nofollow noopener noreferrer\"><code>setup-ocaml<\/code><\/a>, \u0438 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u043c\u043d\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438 (\u043d\u0443\u0436\u043d\u043e \u00ab\u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c\u00bb \u043f\u0430\u043a\u0435\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e, \u0430 \u0437\u0430\u0442\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442). \u0411\u044b\u043b\u043e \u0431\u044b \u043e\u0447\u0435\u043d\u044c \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u0435\u0441\u043b\u0438 \u0431\u044b \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0430 \u043e\u0434\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u0443\u0441\u0442\u0440\u0430\u043d\u044f\u044e\u0449\u0430\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0449\u0430\u044f \u043a\u043e\u0434 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<h4>\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0446\u0435\u043d\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0439<\/h4>\n<p>  OCaml \u0438\u043c\u0435\u0435\u0442 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u0446\u0435\u043d\u0443 \u00ab\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0439\u00bb. \u042f \u043f\u043e\u043a\u0430\u0436\u0443 \u044d\u0442\u043e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435.<\/p>\n<p>  \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u0438 <code>A<\/code>, <code>B<\/code> \u0438 <code>C<\/code> \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c\u044e <code>A<\/code> -> <code>B<\/code> -> <code>C<\/code> (<code>A<\/code> \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u043d\u0430 <code>B<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u043d\u0430 <code>C<\/code>), \u043a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0438\u0436\u0435.<\/p>\n<pre><code class=\"delphi\">module A = struct .. B.foo () .. end module B = struct .. C.bar () .. end module C = struct .. end<\/code><\/pre>\n<p>  \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0440\u0430\u0437\u043e\u0440\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u0443\u044e \u0432 \u043a\u043e\u0434\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043c\u0435\u0436\u0434\u0443 <code>B<\/code> \u0438 <code>C<\/code>. \u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b <code>B<\/code> \u0437\u0430\u0432\u0438\u0441\u0435\u043b \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <code>C<\/code>, \u0430 \u043d\u0435 \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>C<\/code>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u044c\u0441\u044f, \u0435\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c <code>C<\/code> \u043d\u0430 \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u0435 <code>B<\/code>. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<ol>\n<li>\u0418\u0437\u0432\u043b\u0435\u0447\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>C<\/code> \u0432 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 <code>C_intf<\/code><\/li>\n<li>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c <code>B<\/code> \u043a\u0430\u043a \u0444\u0443\u043d\u043a\u0442\u043e\u0440, \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 <code>C_int<\/code><\/li>\n<\/ol>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u044d\u0442\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a, \u043a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0438\u0436\u0435. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e <code>B<\/code> \u0442\u0435\u043f\u0435\u0440\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u043c, \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0449\u0438\u043c \u043c\u043e\u0434\u0443\u043b\u044c, \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0449\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443 <code>C<\/code> \u0441 \u0438\u043c\u0435\u043d\u0435\u043c <code>C_intf<\/code>.<\/p>\n<pre><code class=\"delphi\">module A              = struct .. B.foo () .. end module B (C : C_intf) = struct .. C.bar () .. end module C              = struct .. end<\/code><\/pre>\n<p>  \u041d\u043e \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e <code>B<\/code>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f <code>A<\/code>, \u0442\u0435\u043f\u0435\u0440\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u043c, \u0430 \u043d\u0435 \u043c\u043e\u0434\u0443\u043b\u0435\u043c. \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0432\u044b\u0448\u0435 \u0448\u0430\u0433\u0438 \u0438 \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c <code>B<\/code> \u0438\u0437 <code>A<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"delphi\">module A (B : B_intf)          = struct .. B.foo () .. end module B (C : C_intf) : B_intf = struct .. C.bar () .. end module C                       = struct .. end<\/code><\/pre>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e. \u041a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0438\u043c\u0435\u0435\u0442 \u0434\u0432\u0430 \u0442\u0438\u043f\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439:<\/p>\n<ul>\n<li>(\u0430) \u041a\u0430\u043a \u043c\u043e\u0434\u0443\u043b\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439<\/li>\n<li>(\u0431) \u041a\u0430\u043a \u043e\u0442 \u043c\u043e\u0434\u0443\u043b\u044f \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438<\/li>\n<\/ul>\n<p>  \u041c\u043e\u0442\u0438\u0432\u0430\u0446\u0438\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0443\u043b\u044f \u0432 \u0444\u0443\u043d\u043a\u0442\u043e\u0440 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 (\u0430), \u043e\u0434\u043d\u0430\u043a\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u044f \u0432 \u0444\u0443\u043d\u043a\u0442\u043e\u0440 \u0442\u0430\u043a\u0436\u0435 \u043c\u0435\u043d\u044f\u0435\u0442 \u0438 (\u0431). \u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, <strong>\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u044f \u0432 \u0444\u0443\u043d\u043a\u0442\u043e\u0440 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u043d\u044f\u0435\u0442 \u0442\u043e, \u043a\u0430\u043a \u043c\u043e\u0434\u0443\u043b\u044c <em>\u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442<\/em> \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439, \u043d\u043e \u0438 \u0442\u043e, \u043a\u0430\u043a <em>\u043e\u0442 \u043d\u0435\u0433\u043e \u0437\u0430\u0432\u0438\u0441\u044f\u0442<\/em> \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438<\/strong>.<\/p>\n<p>  \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u0435\u0435, \u0435\u0441\u043b\u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 <code>B<\/code> \u0438\u043b\u0438 \u0435\u0441\u043b\u0438 \u0433\u0440\u0430\u0444 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0431\u043e\u043b\u0435\u0435 \u0433\u043b\u0443\u0431\u043e\u043a\u0438\u0439.<\/p>\n<p>  \u0421\u0442\u043e\u0438\u0442 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u0432 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0435 \u041e\u041e\u041f. \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 <code>B<\/code> \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u043b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>C_intf<\/code> \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 <code>C<\/code>, \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442 \u0442\u0438\u043f \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 <code>B<\/code> [\u041e\u0434\u043d\u0430\u043a\u043e \u0432 \u041e\u041e\u041f \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0440\u0430\u0441\u043f\u043b\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_dispatch\" rel=\"nofollow noopener noreferrer\">\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439. \u0422\u0430\u043a\u0436\u0435, \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u041e\u041e\u041f \u0432 OCaml, \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u0435\u0448\u0430\u0442\u044c \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044f\u043c \u043a\u043e\u0434\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u043d\u043e\u0433\u0438\u0435 \u043b\u044e\u0434\u0438 (\u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438 \u044f) \u043d\u0435\u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u041e\u041e\u041f-\u0430\u0441\u043f\u0435\u043a\u0442\u043e\u043c OCaml.].<\/p>\n<p>  \u0420\u0430\u0431\u043e\u0442\u0430\u044f \u043d\u0430\u0434 CAMLBOY, \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439, \u043a\u043e\u0433\u0434\u0430 \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u043e\u0439 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f (\u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u0433\u0440\u0430\u0444 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 <code>Camlboy<\/code> -> <code>Bus<\/code> -> <code>Cartridge<\/code> \u0438 \u044f \u0445\u043e\u0442\u0435\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0447\u0430\u0441\u0442\u044c \u0441 <code>Bus<\/code> -> <code>Cartridge<\/code>).<\/p>\n<h1>\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b<\/h1>\n<p>  <\/p>\n<h2>\u041f\u0440\u043e OCaml<\/h2>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/janestreet\/learn-ocaml-workshop\" rel=\"nofollow noopener noreferrer\">Learn OCaml Workshop<\/a><br \/> \n<ul>\n<li>\u041a\u0440\u0430\u0439\u043d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0432\u043e\u0440\u043a\u0448\u043e\u043f\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432 Jane Street. \u041e\u043d \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0438\u0437 \u043a\u043e\u0434\u0430 OCaml \u0441 \u0434\u044b\u0440\u0430\u043c\u0438 \u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u044b\u0440, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0437\u0443\u0447\u0430\u0442\u044c OCaml \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435. \u0412\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043a\u043d\u0438\u0433\u0438 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Snake and Lumines, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0442\u043e\u043c\u0443, \u043a\u0430\u043a \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u0438, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0442. \u043f.<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/dev.realworldocaml.org\/\" rel=\"nofollow noopener noreferrer\">Real World OCaml<\/a><br \/> \n<ul>\n<li>\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u044d\u0442\u0443 \u043a\u043d\u0438\u0433\u0443, \u0435\u0441\u043b\u0438 \u0432\u044b \u0437\u043d\u0430\u0435\u0442\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 OCaml \u0438\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0435 \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u044f\u0437\u044b\u043a\u0430\u043c\u0438. \u0412 \u043d\u0451\u043c \u0438\u0437\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u0437\u043d\u0430\u043d\u0438\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u00ab\u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445\u00bb \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u043d\u0430 OCaml \u0441 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  <\/p>\n<h2>\u041f\u0440\u043e Game Boy<\/h2>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=HyzD8pNlpwI\" rel=\"nofollow noopener noreferrer\">The Ultimate Game Boy Talk<\/a><br \/> \n<ul>\n<li>\u041e\u0442\u043b\u0438\u0447\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0441\u0435\u0433\u043e \u0437\u0430 \u0447\u0430\u0441 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 Game Boy. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0435\u0433\u043e \u0431\u0435\u0441\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437.<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/izik1.github.io\/gbops\/\" rel=\"nofollow noopener noreferrer\">gbops<\/a><br \/> \n<ul>\n<li>\u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u0441 \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043a\u043e\u043c\u0430\u043d\u0434 Game Boy. \u0417\u0434\u0435\u0441\u044c \u0438\u0437\u043b\u043e\u0436\u0435\u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430\u044f \u0434\u043b\u044f \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434.<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"http:\/\/marc.rawer.de\/Gameboy\/Docs\/GBCPUman.pdf\" rel=\"nofollow noopener noreferrer\">Game Boy CPU Manual<\/a><br \/> \n<ul>\n<li>\u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e \u0426\u041f. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u044d\u0442\u043e \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434. \u0421\u0442\u043e\u0438\u0442 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 (\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u0430\u0441\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0444\u043b\u0430\u0433\u043e\u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u043e\u0432) \u043e\u0448\u0438\u0431\u043e\u0447\u043d\u044b.<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/gbdev.io\/pandocs\/\" rel=\"nofollow noopener noreferrer\">Pandocs<\/a><br \/> \n<ul>\n<li>\u0412\u0438\u043a\u0438 \u0441 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c. \u042f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u043a \u044d\u0442\u043e\u0439 \u0432\u0438\u043a\u0438 \u043f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 GPU, \u0442\u0430\u0439\u043c\u0435\u0440\u0430 \u0438 \u0442. \u043f.<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/imrannazar.com\/GameBoy-Emulation-in-JavaScript\" rel=\"nofollow noopener noreferrer\">\u0411\u043b\u043e\u0433 \u0418\u043c\u0440\u0430\u043d\u0430 \u041d\u0430\u0437\u0430\u0440\u0430<\/a><br \/> \n<ul>\n<li>\u0422\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 Game Boy \u043d\u0430 JavaScript. \u042f \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u0435\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/645237\/\"> https:\/\/habr.com\/ru\/post\/645237\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/webt\/s7\/wu\/eh\/s7wuehzqqlfkr5xqnzuaqsnmbdw.png\"\/><\/div>\n<p>  <\/p>\n<h1>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h1>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <em>CAMLBOY<\/em> \u2014 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c Game Boy, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u043d\u0430 OCaml, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u041f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0434\u0435\u043c\u043e:<\/p>\n<p>  <strong><a href=\"https:\/\/linoscope.github.io\/CAMLBOY\/\" rel=\"nofollow noopener noreferrer\">\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0434\u0435\u043c\u043e<\/a><\/strong><\/p>\n<p>  \u042f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0432 \u0434\u0435\u043c\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 ROM, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c (\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e <em>Bouncing ball<\/em> \u0438 <em>Rocket Man Demo<\/em>). \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c \u0432 \u043d\u0438\u0445 \u0432 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043d\u0430 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u043c\u0430\u0440\u0442\u0444\u043e\u043d\u0430\u0445 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 60 FPS.<\/p>\n<h2>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/h2>\n<p>  \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0437\u0434\u0435\u0441\u044c:<\/p>\n<p>  <strong><a href=\"https:\/\/github.com\/linoscope\/CAMLBOY\" rel=\"nofollow noopener noreferrer\">https:\/\/github.com\/linoscope\/CAMLBOY<\/a><\/strong>  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-327993","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/327993","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=327993"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/327993\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=327993"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=327993"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=327993"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}