Change of gear

The very last time I wrote a line into this diary, it was April 2015, and today is December 23th of 20191. Quite a while, isn't it? Well, my beautiful boy was born and since then I do spend much more time playing with him. I hope in 4 to 5 years from now I will be able to propose informatics to him as something to play together, in which case I will make progress again in my learning path, but right now building castles with Lego bricks has a much higher priority than building code with bytes bricks.

I wanted to name the title of this chapter as the moment when I changed gear in my working model. It was quite slow and heavily "hand made" until now. It was just like a car travelling in 1st gear with the engine running just above idle but then, I gave a little bit gas and changed to 2nd gear. I was still proceeding very slow with the car going in 2nd gear just above idle, but it was somehow faster than before. The fact is that I have just invented (or discovered? Who knows…) a programming technique that can help to build something a little bit more complex of all what I have done until now.

A different way of using DEBUG.EXE

When using the command a (assembly), DEBUG.EXE has the following noticeably behaviour that I used to my advantage:

  • The character ";" is used to mark the beginning of a comment (DEBUG.EXE ignores all characters after ";" until the end of the line).
  • DB is interpreted as a command during assembly and I can write a sequence of bytes after it.
  • Jumps and calls can be written stating the absolute target address and DEBUG.EXE codes the relative increment in byte for the instruction pointer2.

Additionally, I knew about redirecting inputs and outputs in UNIX/LINUX with use of the characters "<" and ">" so I gave it a try with DOS and it worked exactly in the same way. Based on all the aforementioned points, I wrote again the code of out_a_nibble in the following way:

OUT_NBL.NPP
f 100 17f 90 a 100 ;234567890123456789012345678901234567890123456789012345678901234567890123456789 ;-------10--------20--------30--------40--------50--------60--------70-------79 ;------------------------------------------------------------------------------ ; OUT_NBL: OUT a NIBble ; ; Copyright (C) 2020 - Michele Musci ; Distributed under the GNU Affero General Public License version 3. ; See "https://www.gnu.org/licenses/agpl-3.0.txt" ; ; This procedure returns in AL (bit0 to bit3) the value of the selected nibble ; in BX. The selection is done depending on the value in CX ; ; INPUT: BX = word to select the nibble from ; CX = nibble selection inside the word in BX ; OUTPUT: AL = selected nibble ; REGISTER USAGE: DX ; THIS ONE CALLS: --- ; ; EXAMPLE: BX: CX: AX: ; ABCD 0001 000D ; ABCD 0002 000C ; ABCD 0003 000B ; ABCD 0004 000A ; ; Build it with command: ; debug < out_nbl.npp > out_nbl_dbg.npp ;------------------------------------------------------------------------------ mov ax, bx ; it copies the value in AX. mov dx, cx ; store the value of CX to resume it before exit. ; ; SHR instruction must use CL register: ; before shift | after shift ; -------------+-------------- ; ABC[D] | ABC[D] --> 0 bits shift ; AB[C]D | 0AB[C] --> 4 bits shift ; A[B]CD | 00A[B] --> 8 bits shift ; [A]BCD | 000[A] --> 12 bits shift ; ; Relationship table for the value of shift: ; index | value of shift ; x | y = f(x) ; ------+---------- ; 4 | 12 ; 3 | 8 ; 2 | 4 ; 1 | 0 ; ; Relationship formula for the value of shift: ; y = 4*(x-1) --> CL = 4*(CL - 1) desired target dec cl ; CL = CL - 1 --> CL = (CL - 1) step 1 shl cl, 1 ; CL = 2*CL --> CL = 2*(CL - 1) step 2 shl cl, 1 ; CL = 2*CL --> CL = 2*2*(CL - 1) final step ; ; shr ax, cl ; select the nibble and ax, 000f ; mask remaining bits mov cx, dx ; restore CX before return ; ;------------------------ ; end of procedure ;------------------------ ret d 100 u 100 rbx 0 rcx 12 r n OUT_NBL.BIN w 100 q

This time, I wrote the text into a simple txt-File with name "out_nbl.npp"3. This file is used as input for DEBUG.EXE and I am going to explain the commands, in the sequence as they are, in order to let you understand what is going on here. First of all, I filled a portion of memory in RAM with the opcode 0x 90 (exchange AX with AX or NOP) using the command f 100 17f 90. Soon after, I started assembling directly in RAM at location 0x 01 00 with the command a 100. From this point onwards, the character ; is interpreted as the beginning of a comment so that I could actually write comments. I marked the maximum length of a line to be 79 chars. By exceeding this length, DEBUG.EXE is still working fine but it produces very bad formatting in output. I coded everything without any empty line because an empty line is interpreted by DEBUG.EXE as the exit from assembly mode. In fact, after the command RET, I added an empty line and, from this point onward, I was back in command line mode of DEBUG.EXE. The command d 100 and u 100 are used to display the result of the assembly in memory and the disassembled version of it. The display occurs on file rather than on screen because I redirected the output to a file. The commands from rbx to q were used to create a binary file with the content of RAM starting at location 0x SEG:0100.

After the preparation of the file "out_nbl.npp", I went on the command line of the DOS console and typed the following4:

debug < out_nbl.npp > out_nbl_dbg.npp

As result, I had three files in the folder:

  • "out_nbl.npp", which is the original input file.
  • "out_nbl_dbg.npp", which is the output file created by DOS based on the outputs streamed by DEBUG.EXE.
  • "OUT_NBL.BIN", which is the binary output file created by DEBUG.EXE with the command w 100.

The output file "out_nbl_dbg.npp" created by MS-DOS with the stream of DEBUG.EXE contains \r\r\n at the end of every line which creates formatting problems. If you open the file with Microsoft notepad it looks like ok. If you print it, you see an additional empty line after each line (due to the first \r carriage return character). If you open the file with NOTEPAD++ you see the same effect as if you would send the file later on to the printer (Fig. A).

Fig. A - \r\r\n creates bad formatting
Fig. A - \r\r\n creates bad formatting

I understood the problem when I let me show the special chars in NOTEPAD++. To do that I selected from the menu "View", the "Show Symbol / Show All characters" option (Fig. B).

Fig. B - Show All Characters option in NOTEPAD++
Fig. B - "Show All Characters" option in NOTEPAD++

I solved the problem by searching \r\r and replacing all of them with just \r (Fig. C).

Fig. C - Replacement of \r\r sequence
Fig. C - Replacement of \r\r sequence

Unfortunately, this is a procedure that must be repeated every time one creates a new output file by use of redirection of output.

What I really used a lot was the output file "out_nbl_dbg.npp" to see how DEBUG.EXE did the assembly. With this file, I read the locations in RAM where each command started and I used them as targets for the jumps (and calls) as if these addresses were numbers of lines (in the upcoming posts, I will explain this step more in detail and with examples).

CONCLUSION: the naming convention of files

By each procedure5, I always end having 3 files:

  • fname.npp
  • FNAME.BIN
  • fname_dbg.npp

The "NPP-files" are just text files. The binary file is created directly by DEBUG.EXE. Due to this fact, I have to use 8.3 file name convention (8 chars for name and 3 chars for extension). In fact, I tried to use long names for the "BIN-file" but DEBUG.EXE truncated all by 8.3.
"fname.npp" is always the source file6. It is a plain text file that can be opened and edited with any text editor. The extension "NPP" is what I decide to use in order to make an automatic file association with the NOTEPAD++ editor. There are a couple of features that I like in NOTEPAD++ and this is the reason why I used it, but you can feel free to use whatever text editor you like.
"FNAME.BIN" is the file that is created as the second one directly by DEBUG.EXE with use of commands n and w. It follows strictly the 8.3 filename convention and DEBUG.EXE capitalizes always the filename when it creates it.
"fname_dbg.npp" is the last file created by DOS with the technique of redirecting the output to file. Since this file is created by DOS it is allowed to have long names. The "_dbg" part of the name tells me that this is the place to look at when I need information about the procedure. Here I see the protocol of the assembly job done with DEBUG.EXE.



  1. In july of 2020, I started taking the working notes about my self-learning experience from the paper form (what I call the diary) and bring them to this blog. This post, together with all other posts on the page "the diary", belongs to the original paper-form diary which by reading it now, creates here the effect of a flash-back. [click back]
  2. If you place a call 100 instruction during assembly mode of DEBUG.EXE and later on you check the result with the command u you see the following:
    1379:0149 E8B4FF CALL 0100
    DEBUG.EXE codes 0x E8 B4 FF where 0x E8 is the opcode corresponding to the mnemonic of the instruction CALL and 0x FF B4 is the hexadecimal variation of the instruction pointer register to be used for the execution of the instruction. In fact, IP is equal to 0x 01 4C after that the instruction 0x E8 B4 FF is fetched (but not yet executed) which is the result of 0x 01 49 (start of instruction) + 0x 03 (length of instruction). In two's complement representation, 0x FF B4 is the equivalent of the decimal -76. If you convert everything in decimal and then back in hexadecimal again, we have: 0x 01 4C -> 332; 332 – 76 = 256; 256 -> 0x 01 00. [click back]
  3. The extension ".npp" is used by me in such a way that I can associate this file with NOTEPAD++. Indeed this is just a plain text file that you can open with Microsoft Notepad. [click back]
  4. If you want, you can go to the DOWNLOAD AREA, download the "out_nbl.npp" file and try it yourself. [click back]
  5. The more I look and study into the word of assembly the more I realize that people in the assembly community uses the word "procedure" instead of the word "function". There may be good reasons for that but I don't know any yet. On the very basic, it is always about the code that runs between a CALL and a RET instruction. [click back]
  6. "fname" is just an example here. I used different names for different procedures as I needed. One can generalize the names using the wildcard "*" and say: "*.npp", "*.BIN" and "*_dbg.npp". [click back]

<PREV.  -  ALL  -  NEXT>

Comments