13 December 2003 Adding a record block Now I want to verify that I can store some arbitrary data to the record segment. I'll store a sixteen-byte string into block #1 and use dump_16 to verify that (1) the directory entry for block #1 was written correctly, and (2) the data to be contained in block #1 was written at the correct location. Code The new code does the following: Prepare for a REP MOVSB operation. First, load DI with the address where data is going — in this case, the offset to the first byte beyond the end of the data in the record segment, which is always equal to the data size stored at 0x1000:0000. (In this case, ES is assumed to be pointing to the record segment already. Also note that I need to use the data size in a calculation, so I load it into AX — and the code produced by loading AX and moving to DI is one byte shorter than the equivalent code that loads DI and moves to AX.) mov ax, [es:0] mov di, ax For REP MOVSB, CX must be loaded with the number of bytes to move. mov cx, 16 ; size of block REP MOVSB alters CX, which contains a value I need to calculate the new record-segment data size, so I calculate that now. add ax, cx Normally at this point I'd include jc .error — that is, if the carry flag is set, then there's not enough room in the record segment for the new block, so we can't add it. But that won't happen here, so I simply store the result in the data-size field. mov [es:0], ax Now I write the directory entry for block #1. Note that if the block number is between 1 and 15, the block's entry is stored in the start block. That block's offset field is at offset (block-number x 4), and the block's size field is at offset ((block-number x 4) + 2). So I store the block offset (in DI) to offset 4, and I store the block size (in CX) to offset 6. mov [es:4], di mov [es:6], cx For REP MOVSB, store the segment:offset of the bytes to be copied in DS:SI. DS is assumed to be 0x0000 already, so I load only SI here. mov si, recdata Now move the bytes into the block. (Note that I could have sped things up by halving CX and using REP MOVSW instead, but I'm concentrating on keeping the code small, not making it faster.) rep movsb Now I can dump the contents of the start block (the first 64 bytes of the record segment). call clear_screen mov ax, 0x1000 mov fs, ax xor bx, bx call dump_16 call dump_16 call dump_16 call dump_16 I dump another 16 bytes so that I can show the contents of block #1. The ASCII portion of the dump should say Here's some text. call dump_16 I dump another 16 bytes to show that the space beyond the end of block #1 is all zeroes. call dump_16 jmp $ recdata: db "Here's some text" ; 16 chars long Results Record #0 in the start block should now list a data size of 0x50 (80 -- 64 + 16). The start-block size at offset 2 should still be 0x40 (64). Record #1 in the start block (at offset 4) should show an offset of 0x40 (64) and a size of 0x10 (16). Block #1 (at offset 0x0040 or 64) should contain the characters "Here's some text". Here is the display that appears on my laptop when I run this code: 1000:0000: 50 00 40 00 40 00 10 00 00 00 00 00 00 00 00 00 | P @ @ > 1000:0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 1000:0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 1000:0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 1000:0040: 48 65 72 65 27 73 20 73 6F 6D 65 20 74 65 78 74 | Here's some text 1000:0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | Check the index for other entries. |