{"id":3079,"date":"2025-11-28T00:52:30","date_gmt":"2025-11-27T22:52:30","guid":{"rendered":"https:\/\/www.julien-nevo.com\/arkostracker\/?page_id=3079"},"modified":"2025-12-03T14:14:18","modified_gmt":"2025-12-03T12:14:18","slug":"z80-profiler","status":"publish","type":"page","link":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/z80-profiler\/","title":{"rendered":"Z80 profiler"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A strange alien command-line tool has appeared since 3.5: the Z80 profiler (ZP).<\/p>\n\n\n\n<pre class=\"wp-block-verse\">The Z80 profiler is included, for now, to AT3, but it may be exported to its own repository one day, since it is not really a music tool. However, it was easier for me to set it up this way!<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It is a tool that executes a Z80 binary code and indicates how many NOPs (<em>CPC<\/em> NOPs) it took to execute the code. The code is executed many times, so that you could, say, profile a music player. At the end, the tool indicates the minimum, maximum and average NOP count. It can also produce a CSV report if you want to make some statistics.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Under the hood, a Z80 emulator runs your code as if you were calling the real code on the machine. But much faster!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How it works<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The use is simple, and generic (you could profile a music player, your 3D code, or anything else):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ZP loads your binary file at a given address (AMSDOS header, if any, is skipped).<\/li>\n\n\n\n<li>ZP optionally runs an init code on startup (typically, if you want to initialize a music player). A value in register A can be passed (useful to, say, select a subsong!)<\/li>\n\n\n\n<li>Then, ZP runs the main code 10000 times (this value can be changed).<\/li>\n\n\n\n<li>A report is shown or generated.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">In order to know what to execute, ZP requires a Z80 binary file with a specific format:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Two hooks must be given at the beginning of your code: the init hook (at address +0), and the exec hook (at address +3). Both these addresses can be changed.<\/li>\n\n\n\n<li>Once your init\/exec code is finished, make a jump to #FFFF (this value can be changed).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A typical code would look like this, for the AKY player (but ANY code would work):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    org #4000   ;It can be anything!\n\n    ;Hooks.\n    jp Init     ;Start +0. ZP will jump here to init.\n    jp Exec     ;Start +3. ZP will jump here for each execution.\n\nInit\n    ;Init your code.\n    ;Here, it is the initialization of a player, but it could be anything!\n    ld hl,Music_Start\n    call PLY_AKY_Init\n    jp #ffff    ;Go back to the profiler. This address can be changed.\n\nExec\n    ;This is the piece of code that will be called many times.\n    ;Here, we call the player in order to profile it!\n    call PLY_AKY_Play\n    jp #ffff    ;Go back to the profiler. This address can be changed.\n\nMusic_Start\n    include \"AkyMusic.asm\"\n    include \"AkyMusic_playerconfig.asm\"\n\n    include \"PlayerAky.asm\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Running the tool<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Assemble your code with any assembler. The command-line tool (present in the <em>commandLineTools<\/em> folder) can then simply be called like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Z80Profiler binary.bin<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The default &#8220;load address&#8221; is #4000, but you can change it with the option <code>--loadAddress<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ZP being independent from any machine, you can compile a binary at 0, or any address you feel like! Watch our however:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The interruptions are disabled.<\/li>\n\n\n\n<li>The stack pointer is set at #FFFF by default (first written word is thus #FFFD \/ #FFFE).<\/li>\n\n\n\n<li>The &#8220;exit&#8221; address is #FFFF by default.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If these last bullet points bothers you, use the option <code>--spAddress<\/code> and <code>--stopAddress<\/code> to change them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The output for the above could look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Loaded the file in 0x4000.\nCalling the initializaton code from address 0x4000.\nInit code NOPs: 55\n\nCalling the exec code from address 0x4003, 10000 times...\nExec code iteration 0. NOPs: 712\nExec code iteration 1000. NOPs: 546\nExec code iteration 2000. NOPs: 499\n...\n\nProfiling done!\nMinimum NOPs: 458\nMaximum NOPs: 811\nAverage NOPs: 539<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Handy, right?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are many options in this tool, so don&#8217;t hesitate to check them out (run the tool without parameter to get the help).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">NOP counting<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Things to know about the NOP counting:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The NOP counting mechanism uses the &#8220;CPC&#8221; way of counting cycles. It differs a bit from other hardware. If you&#8217;re interested in me adding other options, please let me know!<\/li>\n\n\n\n<li>The counting shown already takes in account the hooks (JP at +0\/+3) and the <code>JP #FFFF<\/code> in your init\/exec code.<\/li>\n\n\n\n<li>If your setup has more instructions in the exec code (calling the player, doing this or that&#8230;), use the <code>--execOverheadNops<\/code> to indicate of how many NOPs to subtract to the end result (5 in the above case (<code>call PLY_AKY_Play<\/code>)).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping up<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This small tool is experimental and still very young. I&#8217;d like to thank <strong>Krusty<\/strong> for suggesting it to me! Also thanks to <strong>Roudoudou<\/strong> for helping correct some instruction timings. ZP probably lacks some options I didn&#8217;t think of, so don&#8217;t hesitate to contact me if you have any!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A strange alien command-line tool has appeared since 3.5: the Z80 profiler (ZP). The Z80 profiler is included, for now, to AT3, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":214,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_vp_format_video_url":"","_vp_image_focal_point":[],"footnotes":""},"class_list":["post-3079","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/wp-json\/wp\/v2\/pages\/3079","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/wp-json\/wp\/v2\/comments?post=3079"}],"version-history":[{"count":17,"href":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/wp-json\/wp\/v2\/pages\/3079\/revisions"}],"predecessor-version":[{"id":3108,"href":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/wp-json\/wp\/v2\/pages\/3079\/revisions\/3108"}],"wp:attachment":[{"href":"https:\/\/www.julien-nevo.com\/arkostracker\/index.php\/wp-json\/wp\/v2\/media?parent=3079"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}