⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exa1.html

📁 关于ARM汇编的非常好的教程
💻 HTML
字号:
<!doctype html public "-//W3C//DTD HTML 3.2//EN"><html><head><title>Example 1: Screen image compressor</title><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /><meta http-equiv="content-language" content="en" /><meta name="resource-type" content="document"><meta name="copyright" content="This document copyright 2001 by Richard Murray. Use for non-profit and education purposes explicitly granted."><meta name="author" content="Richard Murray"><meta name="rating" content="general"></head><!--  /assembler/exa1.html               --><!--                                     --><!--  (C) Copyright 1999 Richard Murray  --><!--  Designed by Richard Murray         --><!--  rmurray@heyrick.co.uk              --><!--                                     --><body bgcolor="#f0f0f0" text="#000000" link="#0022dd" vlink="#002288"><table border = "0" width="100%">  <tr>    <td align=center width=100>      <img src="arm3.gif" width=79 height=78 align = middle>    </td>    <td>      <h1 align="center"><font color="#800080">Example 1<br>Screen image compressor</font></h1>    </td>    <td align=center width=100>      <img src="arm3.gif" width=79 height=78 align = middle>    </td></table><p>&nbsp;<p>What we shall do here is to jump straight in with an example program. Something that you willfind useful (I mean - what <i>is</i> the point of writing &quot;Hello World&quot; a few thousandtimes? When you learn to code it is much better to learn on <i>useful</i> projects).<p>This project is a 16-colour screen mode compressor. It can be adapted to other modes, but I'llleave that as an exercise for the advanced. After all - ChangeFSI does a marvellous job ofreducing the number of colours in an image, and for demos with 'real life screenshots', 16colours is usually adequate (unless you are plugging the latest 16 million colour game you wrote- in which case you won't need this utility!).<p>Average savings depend on the image. It does badly with dithered images, it does well withimages that don't have loads of fiddly things (a screenshot of a program running in an <i>untextured</i> Desktop, for example). It has been designed to work with MODE 12 and MODE 35.For others, it is a case of suck it and see - but there is no real reason why other 16 colourMODEs would not work.<p>Right. Well... In the old days when it was safe to leave your car unlocked and your daughter unchained, screen memory started at &2000000 and worked upwards. You needed to <i>know</i> a fewmodes such as 12 and 13 and 15... Like, who do you know that uses MODE 8?<p>Modern life, however, is not so simple. We would be foolish to assume the screen start position and/or size. We would also be foolish to assume the 'default' palette. So all of this information has to be examined.<br>16 colour modes use 4bpp, or 4 bits per pixel. Thus, one byte equals two pixels.<p>The compression system is appropriately crude. We will work on a &quot;better&quot; scheme later.However for now we shall be using a kind of Run-Length-Encoding. We treat the screen memory as asequence of bytes, and we encode it into a set of byte counts and byte values. For example,assume screen memory is:<br><center><code>111111111142351111121111111222222222222222111111111111</code></center><br>This would be a bunch of 1's followed by a 4, a 2, a 3, a 5, more ones... Which becomes:<br><center><code>A114121315511271F2C1</code></center><br>This has reduced the stream to approximately a third of original size. The &quot;A1&quot; means10 x 1 (A is 10 in base 16). Then 1 x 4, 1 x 2, 1 x 3, 1 x 5, 5 x 1, 1 x 2, 7 x 1, 15 x 2 andfinally 12 x 1.<p>If you don't get it, study the above for a few moments. It is quite simple once you understand.By way of example, <code>11112246885788</code> becomes <code>4122141628151728</code>; and you cansee how it becomes inefficient with oft changing bytes (such as dithered images), the output istwo bytes larger than the input.<p>&nbsp;<p>&nbsp;<p>Our format is to be defined as:<br><pre>   Header:  &quot;BudgieScrn (compressed 1)&quot;+&lt;newline&gt;            which is 26 bytes.   Mode:    1 byte giving mode number.   Palette: 16 entries, six bytes each. Giving red, green and            blue values for first flash colour and second            flash colour for each entry.   Image:   Data as defined above.</pre>We will leave the screen size validation up to the loader instead of encoding it into the image.<p>So... Let us begin:<pre>REM &gt;Ssaver BudgieSoft screen saverREM V1.01 &copy; 1997 Richard MurrayREMREM Assembler programming example 1REM Downloaded from: http://www.heyrick.co.uk/assembler/:ON ERROR PRINT REPORT$+&quot; at &quot;+STR$(ERL/10) : END:DIM code% &amp;400FOR pass% = 4 TO 6 STEP 2  P%=0  O%=code%  [ OPT pass%</pre>This is a fairly standard beginning. The thing to note is that we are using offset assembly. Inthis way, our code is compiled as a transient utility instead of an &quot;absolute&quot;application. It should also be loadable.The divide-by-ten in the error message is so that 'real lines' match up to !Edit lines, so ifyou get an error just press F5 and enter that number.<pre>    MOV    R7, R14</pre>We now 'save' the return address in register 7. This is so that it does not get overwritten byBL (Branch with Loop) stuff. Note, if you want to fiddle with the code - remember register 7 is<i>special</i>.<pre>    MOV    R0, #&amp;8C    SWI    &quot;XOS_Find&quot;    BVS    exit    MOV    R6, R0</pre>Our program is designed to be called as &quot;SSaver &lt;filename&gt;&quot;. Conveniently theOS_Find call (opens/closes files) has a flag to look for the filename in the entry parameters.So this stuff attempts to open our file with write access. If it fails the V flag (oVerflow) isset. The BVS command (Branch if V Set) will carry us out to a safe exit. Otherwise we can assumeall went well, and move our file handle into register 6 for safe keeping.<p>By now we have our file open and are ready to start building up our image data.<pre>    MOV    R0, #2    MOV    R1, R6    ADR    R2, header_text    MOV    R3, #26    SWI    &quot;XOS_GBPB&quot;    BVS    error</pre>This sets up a call to OS_GBPB to write the header; which is defined at the end as&quot;.header_text&quot;. The BVS takes us to an error handler in case we don't havewrite-access after all! <pre>    MOV    R0, #&amp;87    SWI    &quot;XOS_Byte&quot;    MOV    R0, R2    MOV    R1, R6    BL     write_byte</pre>If you were to look up OS_Byte &87 in a manual, you might wonder about my sanity. After all -what relevance could &quot;get character at cursor position&quot; have?<p>Frankly - none. :-) However in register 2 it returns the current MODE number, and THAT is whatwe are looking for. We then set up a call to a routine that outputs a byte for us, defined lateras &quot;.write_byte&quot;.<pre>    MOV    R5, #0  .col_loop    MOV    R0, R5    MOV    R1, #16    SWI    &quot;OS_ReadPalette&quot;    MOV    R1, R6    MOV    R0, R2, LSR #8    ; red 1st    BL     write_byte    MOV    R0, R2, LSR #16   ; green 1st    BL     write_byte    MOV    R0, R2, LSR #24   ; blue 1st    BL     write_byte    MOV    R0, R3, LSR #8    ; red 2nd    BL     write_byte    MOV    R0, R3, LSR #16   ; green 2nd    BL     write_byte    MOV    R0, R3, LSR #24   ; blue 2nd    BL     write_byte    ADD    R5, R5, #1    CMP    R5, #16    BLT    col_loop</pre>This looks complicated and I'm not going to explain it to verbosely. However what we are tryingto do here is to read the palette (care of OS_ReadPalette). It returns two registers for the sixcolour values. As we are using 32 bit words, we can cram several 8 bit values into one word.Hence the LSR, which is a Logical Shift Right. LSR takes a value (say %110110100) and shifts it(say two places) to produce an output (such as %001101101). We loop through the 16 colours andextract the six values for each, writing them to the file as we are going along.<p>The header is now complete.<pre>    ADR    R0, vdu_block    ADD    R1, R0, #12    SWI    &quot;OS_ReadVduVariables&quot;    LDR    R2, [R1]    LDR    R3, [R1, #4]    ADD    R3, R3, R2    SWI    &quot;XOS_RemoveCursors&quot;</pre>Even though we are not going to write the screen dimensions to the file; we do need to knowwhere the screen starts and ends. This calls &quot;OS_ReadVduVariables&quot; asking for thescreen base address and the size of the screen. Adding the two gives us our result, with thedata held in the memory area defined later as &quot;.vdu_block&quot;. While we are at it, weswitch the cursor off.<pre>    MOV    R1, R6  .main_loop    LDRB   R0, [R2]    BL     write_byte    MOV    R4, #1  .loop2    LDRB   R5, [R2, #1]!    ADD    R4, R4, #1    CMP    R5, R0    BNE    skip    CMP    R4, #&amp;FF    BLT    loop2  .skip    SUB    R0, R4, #1    BL     write_byte    CMP    R2, R3    BLT    main_loop</pre>Here is the main loop. What it does is it outputs the value of the current byte (ie: the colour)and then it reads through the memory looking to see how long it continues for. As a byte canonly hold 256 different values, it loops up to a maximum of 255. Once a value has beenestablished, it will write it out to the file and then branch back to the main loop; repeatinguntil the end of screen memory is reached.<pre>    MOV    R0, #&amp;20    BL     write_byte    MOV    R0, #&amp;20    BL     write_byte</pre>A really early version of this software messed up by trying to read a little beyond the end ofthe screen (and hence the end of the file), so it became practice to add two spaces to the endof the file - just in case - even though the &lt;cough&gt;bug&lt;/cough&gt; was fixed.<pre>    MOV    R0, #0    MOV    R1, R6    SWI    &quot;XOS_Find&quot;    SWI    &quot;XOS_RestoreCursors&quot;</pre>This wraps up, closing our file and restoring the cursor. It falls through to &quot;.exit&quot;which follows next.<pre>  .exit    MOV    PC, R7</pre>Leave the program - places stored return address (in register 7) into the Program Counter(register 15).<pre>  .write_byte    SWI    &quot;XOS_BPut&quot;    MOVVC  PC, R14</pre>Simple routine to write a byte of data. Not terribly efficient, however you could change it tomove the file handle here instead of beforehand (using MOV R1, R6). It returns by way offunction returning (move return address into Program Counter); but only if the V flag is clear.If something went wrong, however, then we fall through to &quot;.error&quot;...<pre>  .error    MOV    R2, R0    MOV    R1, R6    MOV    R0, #0    SWI    &quot;XOS_Find&quot;    SWI    &quot;XOS_RestoreCursors&quot;    MOV    R0, R2    ORR    PC, R7, #1&lt;&lt;28</pre>This closes the file, restores the cursor and exits with the V flag set (error condition). It isthe 'standard' error handler for this program.<br><font color="red">This is not 32-bit compliant.</font><pre>  .vdu_block    EQUD   149    EQUD   7    EQUD   -1    EQUD   0    EQUD   0</pre>This is the block for the OS_ReadVduVariables command. The 149 and 7 are the codes for thevalues we wish to read. The -1 terminates the list. The two 0's are where the information isplaced by the OS.<pre>  .header_text    EQUS   &quot;BudgieScrn (compressed 1)&quot;    EQUB   10    EQUB   0    ALIGN</pre>This is the header.<pre>  ]NEXT:OSCLI(&quot;Save &lt;Obey$Dir&gt;.Saver &quot;+STR$~(code%)+&quot; &quot;+STR$~(O%))OSCLI(&quot;SetType &lt;Obey$Dir&gt;.Saver &amp;FFC&quot;):END</pre>And finally the denouement. Close the loop, save the file and exit.<p>There you have it!<p>To use it, try an Obey file similar to:<pre>| Obey file to run SSaver|ScreenLoad &lt;Obey$Dir&gt;.mypiccy|&lt;Obey$Dir&gt;.SSaver &lt;Obey$Dir&gt;.comp_piccy</pre>In the next section, we shall create a loader. Before looking at that, why not see if you canfiddle with the above to make it work in reverse?<div align = right><a href="sw/ssaver.basic"><i>Download example: ssaver.basic</i></a></div><p><hr size = "3"><a href="index.html#15">Return to assembler index</a><hr size = "3"><address>Copyright &copy; 1999 Richard Murray</address></body></html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -