-2

i have some what little bit lengthy code but a very small problem in line which is mentioned as "PROBLEM IN THIS LINE" explicitly.why we are adding SI and AX twice(instead of just once).As you will go through the code you will find it very precisely.

DEVSTART LABEL WORD
CONSOLE_DEV:                ;Header for device CON
    DW      AUXDEV,BIOSSEG  ;Link to next device
    DW      8003H           ;Attributes - console input, 
                            ;output device
    DW      STRATEGY        ;Srategy entry point
    DW      CON_INT         ;Interrupt entry point
    DB      "CON     "      ;Device name
;-------------------------------------------------
CONSOLE_TABLE: DW      EXIT ;0  - Init. (Not used)
    DW      EXIT            ;1  - Media check (Not used)
    DW      EXIT            ;2  - Get Bios Parameter Block 
                            ;(Not used)
    DW      CMDERR          ;3  - Reserved. (Currently 
                            ;returns error)
    DW      CON_READ        ;4  - Character read. 
                            ;(Destructive)
    DW      CON_RDND        ;5  - Character read. (Non- 
                            ;destructive)
    DW      EXIT            ;6  - Return status. (Not used)
    DW      CON_FLSH        ;7  - Flush Input buffer.
    DW      CON_WRIT        ;8  - Character write.
    DW      CON_WRIT        ;9  - Character write with 
                            ;Verify.
    DW      CON_WRST        ;10 - Character write status.
    DW      EXIT            ;11 - Flush output buffer. (Not 
                            ;used.)
    DW      EXIT            ;12 - IO Control.
;-----------------------------------------------
    PAGE
    SUBTTL  Strategy and Software Interrupt routines.

    ;Define offsets for io data packet

IODAT   STRUC
CMDLEN  DB      ?               ;LENGTH OF THIS COMMAND
UNIT    DB      ?               ;SUB UNIT SPECIFIER
CMD     DB      ?               ;COMMAND CODE
STATUS  DW      ?               ;STATUS
    DB      8 DUP (?)
MEDIA   DB      ?               ;MEDIA DESCRIPTOR
TRANS   DD      ?               ;TRANSFER ADDRESS
COUNT   DW      ?               ;COUNT OF BLOCKS OR 
CHARACTERS
START   DW      ?               ;FIRST BLOCK TO TRANSFER
IODAT   ENDS

PTRSAV  DD      0               ;Strategy pointer save.

;
; Simplistic Strategy routine for non-multi-Tasking system.
;
;   Currently just saves I/O packet pointers in PTRSAV for
;   later processing by the individual interrupt routines.
;

STRATP  PROC    FAR

STRATEGY:
    MOV     WORD PTR CS:[PTRSAV],BX
    MOV     WORD PTR CS:[PTRSAV+2],ES
    RET

STRATP  ENDP

;
; Console interrupt routine for processing I/O packets.
;

CONSOLE_INT:
    PUSH    SI
    MOV     SI,OFFSET CONSOLE_TABLE
    JMP     SHORT ENTRY
;-------------------------------------------
;
; Common program for handling the simplistic I/O packet
;   processing scheme in MSDOS 2.0
;

ENTRY:  PUSH    AX              ;Save all nessacary 
                                ;registers.
    PUSH    CX
    PUSH    DX
    PUSH    DI
    PUSH    BP
    PUSH    DS
    PUSH    ES
    PUSH    BX

    LDS     BX,CS:[PTRSAV]  ;Retrieve pointer to I/O Packet.

    MOV     AL,[BX.UNIT]    ;AL = Unit code.
    MOV     AH,[BX.MEDIA]   ;AH = Media descriptor.
    MOV     CX,[BX.COUNT]   ;CX = Contains byte/sector 
                            ;count.
    MOV     DX,[BX.START]   ;DX = Starting Logical sector.

    XCHG    DI,AX           ;Move Unit & Media into DI 
                            ;temporarily.
    MOV     AL,[BX.CMD]     ;Retrieve Command type. (1 => 
                            ;11)
    XOR     AH,AH           ;Clear upper half of AX for 
                            ;calculation.

    ADD     SI,AX           ;"PROBLEM IN THIS LINE"
                            ;(Compute entry pointer in dispatch table).
    ADD     SI,AX           ;"PROBLEM IN THIS LINE".

    CMP     AL,11           ;Verify that not more than 11 
                            ;commands.
    JA      CMDERR          ;Ah, well, error out.
    XCHG    AX,DI           ;Move Unit & Media back where 
                            ;they belong.
    LES     DI,[BX.TRANS]   ;DI contains addess of Transfer 
                            ;address.
                            ;ES contains segment.
    PUSH    CS
    POP     DS              ;Data segment same as Code 
                            ;segment.
    JMP     [SI]            ;Perform I/O packet command.

CODE CONTINUES..............

please help, i am deeply regret if you find it odd. but i am sure that i have added enough information in this post. please see lines mentioned as "PROBLEM IN THIS LINE". Please let me know if you need some more details.

Vstbutwhy
  • 73
  • 1
  • 5
  • 3
    Each entry in `CONSOLE_TABLE` is 2 bytes hence you need to double the index. A simple way to do that is to add twice. – Jester Jan 04 '19 at 12:39
  • 2
    what is the error? you have spent a lot of time pleading, but it removed focus from what you are asking. please read [ask] – JoSSte Jan 04 '19 at 12:40
  • dear JoSSte, why we are adding AX to SI in above mentioned lines, what is the purpose behind it. what is the line saying "Compute entry pointer in dispatch table". – Vstbutwhy Jan 04 '19 at 12:47
  • 1
    A more interesting question is why there's a `JMP SHORT ENTRY` instead of simply falling through into ENTRY. There's no self-modifying code here that I can see, and I don't see any other reason to `jmp +0`. – Peter Cordes Jan 04 '19 at 18:11
  • 1
    I like these questions that you've asked so far but I also see that you start getting multiple downvotes. Looking at your profile I find a long list of good answers and/or good comments that you received but that you didn't bother to reward! This forum is based on _voting_. If you want to keep getting useful responses, you should start __upvoting__ and __accepting__ the helpful answers that you get. – Fifoernik Jan 05 '19 at 14:54
  • I just want to know why we are adding AX to SI. – Vstbutwhy Jan 06 '19 at 02:13
  • 1
    @PeterCordes : Because he has snipped out a bunch of other functions that were below CONSOLE_INT and above ENTRY. – Michael Petch Jan 07 '19 at 01:26

2 Answers2

3

The CONSOLE_TABLE is filled with word-sized near pointers. If you want to use e.g. CON_READ which is the 5th item and that bears CommandType aka FunctionNumber 4, you will have to use an offset of 8 within this table.

This is precisely twice the function number!

Therefore adding the function number twice will produce the correct address.

MOV     AL,[BX.CMD]     ;Retrieve Command type. (1 => 11)
XOR     AH,AH           ;Clear upper half of AX for calculation.

Very important! At this point SI already holds the address of the CONSOLE_TABLE.

ADD     SI,AX           ; Add function number once
ADD     SI,AX           ; Add function number twice

The alternative solution of adding the doubled function number is just as simple.

MOV     AL,[BX.CMD]     ;Retrieve Command type. (1 => 11)
XOR     AH,AH           ;Clear upper half of AX for calculation.

Very important! At this point SI already holds the address of the CONSOLE_TABLE.

SHL     AX,1            ; Doubling the function number gives offset
ADD     SI,AX           ; Add full offset

The most misleading element in this program is the all too generically named label ENTRY. The real entry point is of course CONSOLE_INT where SI is preserved and then set up to point to the start of the CONSOLE_TABLE.

Probably the original programmer has more of these PUSH SI MOV SI, ... JMP ENTRY snippets in the sofware.

CONSOLE_TABLE:
+0  == 0*2   EXIT       ;0  - Init. (Not used)
+2  == 1*2   EXIT       ;1  - Media check (Not used)
+4  == 2*2   EXIT       ;2  - Get Bios Parameter Block (Not used)
+6  == 3*2   CMDERR     ;3  - Reserved. (Currently returns error)
+8  == 4*2   CON_READ   ;4  - Character read. (Destructive)
+10 == 5*2   CON_RDND   ;5  - Character read. (Non-destructive)
+12 == 6*2   EXIT       ;6  - Return status. (Not used)
+14 == 7*2   CON_FLSH   ;7  - Flush Input buffer.
+16 == 8*2   CON_WRIT   ;8  - Character write.
+18 == 9*2   CON_WRIT   ;9  - Character write with Verify.
+20 == 10*2  CON_WRST   ;10 - Character write status.
+22 == 11*2  EXIT       ;11 - Flush output buffer. (Not used.)
+24 == 12*2  EXIT       ;12 - IO Control.
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • 3
    The OP has been playing with the published MS-DOS 2.0 source code for a month+ now. If you'd like to see the source material specific to the code above, you can find this specific file here: https://github.com/Microsoft/MS-DOS/blob/master/v2.0/source/SKELIO.ASM . My impression is that the OP has been trying to build the source code and is trying to modernize the source tree to be able to assemble it. – Michael Petch Jan 07 '19 at 01:24
2

I just want to know why we are adding AX to SI.

As opposed to some other way of calculating the same thing? Not clear what you're still wondering about after Jester's comment answered the question right away. If this didn't make sense to you, maybe you need to start writing some code yourself and/or looking at compiler output for C you understand, to get comfortable with x86 and asm, so you'll be able to read other people's code.


There's JMP [SI] later to dispatch to the handler code for that command, so they're calculating an address in SI. (It's indexing a table of words, so adding twice converts a word index to a byte offset. x86-16 doesn't have scaled-index addressing modes.)

Different wrapper stubs before the common ENTRY set SI to the base of different tables. Apparently you removed all of them except CONSOLE_INT: from the code (that's why there's an apparently useless jmp short ENTRY which would assemble to jmp +0 here), but the one you left in has MOV SI,OFFSET CONSOLE_TABLE.

If not for needing to support multiple tables, they could have calculated just a byte offset in SI or DI and used jmp [CONSOLE_TABLE + DI]. But zero-extending a byte into SI or DI is inconvenient on pre-386 without MOVZX, because there's no upper-half/lower-half separately accessible registers.

If they'd been willing to destroy BX, they could have done the following to save an instruction. But presumably they need to keep the pointer to the struct to access other members later.

 MOV   bl, [BX.CMD]
 xor   bh, bh
 add   bx, bx       ; word index -> byte offset
 ...
 jmp [bx+si]        ; BX can be a base register, unlike AX

If they'd wanted to do add ax,ax to double it before adding to SI, they could have done the CMP AL,11 earlier, before calculating the final pointer, or simply done cmp al, 22 after doubling AX.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847