2

Recently I was writing assembly and the program I wrote ran without any problems under DOSBox. Now I need to port the same program into a real computer using DOS but some problems arised.

First of all, under DOSBox I was compiling with ML, but on the real PC once I type in ML it says:

This program cannot be run in DOS mode.

Therefore I was looking for a solution amd found out that MASM can compile asm program without problems. Unfortunately, the program which I need to port reports severe errors (1 type only) while compiling.

error A2061: Improper use of segment register

The lines at which these problems arise are the following

...
CARLOC EQU $-2
...
MOV [WORD PTR DS:CARLOC],DX
...

Also the same problem arises with the following code

...
MOV ES,CX
MOV AL, [BYTE PTR ES:0017H]
...

So far I have tried to change this BYTE PTR into BYTE PTR [ES:0017H] which produced the same error

And into BYTE PTR ES:0017H which compiled the code successfully, the program ran but did not work correctly

Note: I do not know under which architecture am currently working. And probably won't be able to access the machine physically, but if there is some code that I can type in to see the information on screen I will be glad to do so.

Code is here, it is too long for here if i need to paste it here then ok, but until then https://pastecode.xyz/view/5f332efc

The PC says it runs MSDOS 6

14
  • When you say "[n]ow I need to port the same program into a real computer using DOS", do you really mean you want to run it in the Windows command prompt application? Then you can't, because that "DOS prompt" isn't really DOS, it's still Windows and as such won't run old 16-bit applications. Commented Oct 1, 2019 at 10:15
  • Well on the pc it looks like CMD, but I am running the program.exe and the first screen pops up but after my solution the program freezes. Commented Oct 1, 2019 at 10:17
  • 1
    You also can't just build an old 16-bit DOS program that assumes it's in full control of the whole computer, and run it in Windows. You need to translate the code to be able to handle the modern shared environment that protected mode Windows is. Commented Oct 1, 2019 at 10:18
  • Why was this tagged emu8086? You were using DOSBox, not emu8086 originally, and now you're trying to run it natively in a 32-bit or 64-bit executable. Neither of those is emu8086. Commented Oct 1, 2019 at 10:44
  • 1
    [word ptr ds:carloc], dx produced error,but word ptr ds:[carloc], dx does not and [carloc],dx gives error a4057 illegal size for operand. Commented Oct 1, 2019 at 11:18

2 Answers 2

7

(Update: Michael Petch says some MASM or MASM compatible assemblers allow size and segment overrides inside the brackets. But update2: not all, so this may actually have been the problem. It's at least more standard style so I'd recommend always doing that.)


In normal MASM syntax you want MOV [CARLOC], DX. Depending how you declared carloc, you may still need mov word ptr [CARLOC], dx, but DS: is already the default segment.

If you wanted to be explicit about it, MOV word ptr ds:[CARLOC], dx but I recommend leaving out redundant DS prefixes in the asm source because some assemblers include a redundant DS prefix in the machine code! The only time DS: isn't redundant is when used with ds:[bp] or ebp, or ds:[esp], which imply SS as the default segment.

With MASM, ds: prefixes are also requires with numeric absolute addresses. Otherwise that's treated as an immediate (regardless of brackets) which of course can't be a destination. With a definition like CARLOC equ $-2, you will need ds:[CARLOC]. Apparently MASM does not put useless ds prefixes in the machine code so you don't have to worry with that assembler.

If you need a CS/DS/ES/FS/GS/SS prefix, the standard syntax is to put it outside the brackets:

MOV AL, ES:[0017H]

The AL destination implies byte ptr operand-size, which also goes outside the brackets. Look at disassembler output for example.

And into BYTE PTR ES:0017H which compiled the code successfully,

Yes, that is valid syntax: the brackets are optional in some cases (including with absolute addresses or symbols). Many people recommend always using brackets around memory operands (as opposed to OFFSET symbol immediates) to make it clearer for human readers.

If you are going to use brackets, they go after the size ptr and seg: overrides.

the program ran but did not work correctly

Then either your code has other bugs beyond the syntax errors.

Or if you're trying to build this into a Windows executable: Of course it doesn't work to take code written for DOS (real mode, in control of the whole machine) and build it as a 32-bit or 64-bit Windows executable (protected mode or 64-bit mode, ring 3 under an OS). The system-call ABI and even API are totally different, too: those are different OSes and the DOS API isn't available to Windows executables.

Michael also suggested that a USE32 or other directive might make MASM try to save you from yourself and reject use of segmentation in code that's supposed to run with a flat memory model. But if es:[17H] works then that's probably not it.

Sign up to request clarification or add additional context in comments.

9 Comments

@MichaelPetch: ah that would make sense if MASM has a mode that disallows segmented addressing. I did un-bold some parts of my answer, leaving the probably-still-relevant part that the OP's idea of building DOS code as a native Windows executable is doomed.
Typo: MOV [CARLOC], DS - (I think you mean DX here).
@500-InternalServerError: That typo was in the original question; I guess I should clarify or just change my answer to match since this question isn't about whether you can store segment registers to memory. (You can). The OP noticed their own typo and updated their question after an incorrect answer suggested mov ax,ds and storing AX.
MASM retains type information. If you define CARLOC as CARLOC $-2 MASM doesn't consider that an immediate value since it is relative to a label. In that case mov word ptr [CARLOC], dx is legal. However, if CARLOC resolves to an immediate value then mov word ptr [CARLOC], dx will error with immediate mode illegal. This is a case where you actually need a segment override even if it is DS (which may be the default but is required anyway). This works mov word ptr DS:[CARLOC], dx . The general case is that mov word ptr DS:[CARLOC], dx works whether CARLOC is immediate or not.
@MichaelPetch: I thought I remembered some case where some assembler needed some source syntax that resulted in a redundant prefix, so the most efficient encoding was only available by hand. Thanks for confirming MASM isn't like that. (In NASM a ds in the source is never required if you don't want the prefix. So it's also definitely not what I was remembering. I actually use NASM and GAS and would know if either of them had horrible forced wastage of bytes.)
|
5

It is unclear what part of this question I should answer.

  • The original error was related to a typo. DS should have been DX
  • Version 5.10 of MASM you use doesn't support the segment and size overrides inside the square brackets []. Code like this:

    MOV     [WORD PTR DS:CARLOC],DX
    

    Needs to be written as:

    MOV     WORD PTR DS:[CARLOC],DX
    
  • The version of MASM and LINK you are using doesn't generate COM programs. You need a program that used to come with DOS called EXE2BIN that could convert certain types of EXE programs to COM. You'd have to run EXE2BIN like this:

    EXE2BIN progname.exe progname.com
    
  • The version of MASM doesn't support the simplified segment directives .MODEL, .CODE, .DATA, and .STACK that I am aware of so they need to be removed.


Rather than use EXE2BIN to convert from an EXE to a COM program you can modify the code to run as an EXE program. Remove the lines:

    .MODEL  TINY
    .CODE
    .ORG 100h

Create a STACK segment with something like:

STACK SEGMENT STACK
    db 512 DUP(?)
STACK ENDS

An EXE program needs to initialize the DS (and ES if necessary) early on at the program start. This is unlike COM programs where CS=DS=ES=SS and no such initialization is necessary. You'd add these lines to initialize DS:

    MOV     AX, CODE                ; Initialize the Code Segment
    MOV     DS, AX

You placed all your data in the CODE segment so you need to initialize DS to be the same as CODE.

The final version of the program that should run as an EXE is:

        TITLE   FormulaONE TURBO (256 byte game)


STACK SEGMENT STACK
    db 512 DUP(?)
STACK ENDS

CODE    SEGMENT BYTE PUBLIC 'CODE'
        ASSUME  CS:CODE,DS:CODE

;--------------------------------------------------------------------------
;                       ACTUAL PROGRAM BEGINS HERE
;--------------------------------------------------------------------------
START:
        MOV     AX, CODE                ; Initialize the Code Segment
        MOV     DS, AX
        MOV     BP,AX                   ; Reset score to 0 (=MOV BP,0)
        MOV     AH,06H                  ; Clear Screen and home the cursor
        CALL    SCROLL
;--------------------------------------------------------------------------
;                             MAIN GAME LOOP
;--------------------------------------------------------------------------
GAME:
        MOV     DX,1629H                ; Load CAR loc (LINE 16H, COL 29H)
CARLOC  EQU     $-2                     ; Self modifying code (CAR loc)

        CALL    MOVEIT                  ; Move cursor to DH,DL (car loc)
;--------------------------------------------------------------------------
;  Erase the car at old screen location
;--------------------------------------------------------------------------
        MOV     AL,20H                  ; Print 5 spaces
        PUSH    AX
        OUT     61H,AL                  ;   Turn off speaker (AL=00100000b)
        MOV     BL,70H                                                ;^^
        MOV     CL,5
        INT     10H

        MOV     AX,0E0AH                ; Move cursor to next line
        INT     10H

        POP     AX                      ; Print 5 more spaces
        INT     10H
;--------------------------------------------------------------------------
;  Move to new car location based on shift key status
;--------------------------------------------------------------------------
        MOV     CL,40H                  ; Get shift key status
        MOV     ES,CX                   ;   (=MOV ES,0040H)
        MOV     AL,BYTE PTR ES:[0017H]

        TEST    AL,1                    ; Right SHIFT key pressed?
        JZ      TRYLFT                  ;    No...Try left shift
        INC     DX                      ;    Yes..move car right 1 space
TRYLFT: TEST    AL,2                    ; Left SHIFT key pressed?
        JZ      KEYEND                  ;    No...done checking keys
        DEC     DX                      ;    Yes..move car left 1 space
KEYEND: MOV     WORD PTR DS:[CARLOC],DX ; Save new car location in memory
                                        ; (That is the self-modifying part)
        PUSH    DX                      ; Save car location on stack also
;--------------------------------------------------------------------------
;  Scroll the track down one line
;--------------------------------------------------------------------------
        MOV     AX,0701H                ; Scroll screen down 1 line
        CALL    SCROLL                  ;   this also sets BH=0 and BL=2
                                        ;   and homes the cursor

        MOV     CL,40                   ; Print left side of track
LMARGN  EQU     $-1                     ;   (Pointer to Left Margin)
        INT     10H

        MOV     DX,CX                   ; Find right side of track position
        ADD     DX,26                   ;   (Starting track width = 26)
TRKWID  EQU     $-1                     ;   (Pointer to Track Width)
        MOV     CL,80
        SUB     CX,DX
        CALL    MOVEIT                  ; Move cursor to right side of track
        INT     10H                     ; Print grass on right side of track
;--------------------------------------------------------------------------
;  Print the score in the lower right corner of the screen
;--------------------------------------------------------------------------
        MOV     DX,184EH                ; Screen loc 77,25 bottom right
        CALL    MOVEIT                  ; Move cursor to score location
        MOV     AX,BP                   ; Move Score to AX
        MOV     CL,8                    ; Shift score right 8 bits
        SAR     AX,CL                   ; (This makes it hard to get to Z!)
        ADD     AX,0E00H+65             ; MOV AH,0Eh & Convert score to A-Z
        INT     10H                     ; Print the score on the screen
;--------------------------------------------------------------------------
;  Check for a collision
;--------------------------------------------------------------------------
        POP     DX                      ; Restore car location from stack
        CALL    MOVEIT                  ; Move cursor under left front tire
        JNZ     PCAR                    ; Hit something? Yes... Print our
                                        ;   red car and exit the game
        PUSH    DX                      ; Save left tire position to stack
        ADD     DL,4                    ; Move cursor under right front tire
        CALL    MOVEIT                  ; Check to see if we hit something
        POP     DX                      ;    Restore our car position
        JNZ     PCAR                    ; Hit something? Yes... Print our
                                        ;   red car and exit the game
        PUSH    DX                      ; Save car position to stack
;--------------------------------------------------------------------------
;  No collision, go ahead and print our car (red)
;--------------------------------------------------------------------------
        CALL    PCAR                    ; Print our red car (CX=8)
;--------------------------------------------------------------------------
;  Slow game down by waiting for 3 vertical retraces and play sound effects
;--------------------------------------------------------------------------
        MOV     CL,3                    ; CX is delay invertical retraces
DELAY:  MOV     DX,03DAH                ; Video screen port
HERE:   IN      AL,DX                   ; Get current video status
        TEST    AL,8                    ; Check vertical retrace bit
        JNE     HERE                    ; Wait for 1 full vertical retrace
HERE2:                                  ; Turn on and off speaker...
        ADD     AL,BYTE PTR DS:[005DH]  ;   (Check command line for Q)
        DEC     AX                      ;   (which is for Quiet mode.)
        OUT     61H,AL                  ; while waiting for screen refresh
        IN      AL,DX
        TEST    AL,8
        JE      HERE2
        LOOP    DELAY                   ; Go wait for another until CX=0
;--------------------------------------------------------------------------
;  Keep track of our current score
;--------------------------------------------------------------------------
        INC     BP                      ; Count lines printed so far (score)
;--------------------------------------------------------------------------
;  Adjust size and placement of track
;--------------------------------------------------------------------------
        POP     DX                      ; Restore our car position fm stack
        MOV     AX,BP                   ; TEST AL=2 bytes, TEST BP=4 bytes

        TEST    AL,255                  ; Make track smaller each 256 lines
        JNZ     NOCHG                   ;   Go around if not time for change
        DEC     BYTE PTR DS:[TRKWID]    ;   Change width (Self-mod code!)
NOCHG:

        TEST    AL,9                    ; Make track wavy every so often
        JNZ     ENEMY                   ;  Time to go straight
        TEST    AL,128                  ;  Left or right?
        JZ      LEFT
        ADD     BYTE PTR DS:[LMARGN],2  ; -Move right 2 spaces (Self-mod!)
;        INC     DX                      ;    Make sure that enemy car
;        INC     DX                      ;      stays ON the track. (TAI)
LEFT:   DEC     BYTE PTR DS:[LMARGN]    ; -Move left 1 space   (Self-mod!)
;        DEC     DX                      ;    Make sure that enemy car
                                        ;      stays ON the track. (TAI)
;--------------------------------------------------------------------------
;  Draw an opponent car every 15 screen lines
;--------------------------------------------------------------------------
ENEMY:                                  ; Our car position is in DX register
        MOV     DH,0                    ; Make it into enemy position using
                                        ; True Artificial Intellegence (tm)
                                        ; ^    ^          ^  TAI :-)
        TEST    AL,15                   ; Every 15 lines print enemy car
        MOV     AX,OFFSET GAME          ;    Prepare for RET below
        PUSH    AX                      ;    Use RET as a jump to GAME loop
        JNZ     GOBACK                  ; Not time yet to print enemy car
;--------------------------------------------------------------------------
;                PRINT CAR AT SCREEN LOCATION "DX"
;
; On entry:  DH points to line, DL to column, CX to car graphic offset
;                                             (8 for red, 0 for blue car)
; On exit:  The proper car will be drawn.  Also, if we used CALL PCAR to
;           get here we will be returned into the program at that point.
;           If we used JNZ PCAR to get here we will be returned to the
;           DOS prompt (the game will end).
;--------------------------------------------------------------------------
PCAR:
        PUSH    BP                      ; Save our current score counter
        MOV     BP,OFFSET CAR2          ; Point to the car graphic
        ADD     BP,CX                   ;   Add offset to proper car
        SUB     BYTE PTR [BP+4],24      ; Print stripe on hood of car
        MOV     AX,1302H                ; Print the car to the screen
        PUSH    AX                      ;    AX may change in INT 10h call
        MOV     CL,5                    ;    Graphic is 5 characters wide
        PUSH    DS                      ;    It is located in the data seg
        POP     ES                      ;      but INT 10h needs that in ES
        INT     10H                     ; Print the first line of the car
        ADD     BYTE PTR [BP+4],24      ; Print cockpit and rear stripe
        POP     AX                      ; (=MOV AX,1302H)
        INC     DH                      ; Point to next line of the screen
        INT     10H                     ; Print the second line of the car
        POP     BP                      ; Restore current score counter
GOBACK: RET
CAR2:  
        DB      0DCH,70H,0DEH,71H,0D2H,1FH,0DDH,71H     ; Blue car graphic
        DB      0DCH,70H                                ;   Common tire
        DB      0DEH,74H,0D2H,4EH,0DDH,74H,0DCH,70H     ; Red car graphic
;--------------------------------------------------------------------------
;                     SCROLL SCREEN DOWN "AL" LINES
;                      (or if AH=6, clear screen)
;
; On entry:  AH must be 7, AL must be number of lines to scroll (1)
; On exit:   BH will be 0, BL will be 2 and we will fall through to
;            MOVEIT to home the cursor.             ^^^^^^^^^^^^
;--------------------------------------------------------------------------
SCROLL:
        MOV     BH,70H                  ; Use Black on Gray (road color)
        XOR     CX,CX                   ;   From UL corner (=MOV CX,0)
        MOV     DX,184FH                ;   to LR corner
        INT     10H
        MOV     BX,02                   ; Set BH to 0 and BL to 2 for use
                                        ;   when we return.
        XOR     DX,DX                   ; Now, home the cursor  (=MOV DX,0)
;--------------------------------------------------------------------------
;                  MOVE CURSOR TO SCREEN LOCATION DH,DL
;               AND SEE IF THERE IS A SPACE (TRACK) THERE
;
; On entry:  DH is screen line, DL is screen column
; On exit:   Z flag will be set/reset if there is a space character
;            under the cursor and AH will be 9 and AL will be 0DBh
;--------------------------------------------------------------------------
MOVEIT:
        MOV     AH,2                    ; Move cursor to DH,DL
        INT     10H
        MOV     AH,8                    ; Get the character under cursor
        INT     10H
        CMP     AL,20H                  ; Is it a space? (set Z flag)
        MOV     AX,09DBH                ; Set AH to 9 and AL to 0DBh for
        RET                             ;  use just after we return (don't
                                        ;  worry, Z flag will still be set)
CODE    ENDS

        END     START

Reply to "Stackoverflow question a2061"
Author
Title
Re: Stackoverflow question a2061
Language

Your paste - Paste your paste here
        TITLE   FormulaONE TURBO (256 byte game)
;==========================================================================
;      FormulaONE TURBO Copyright 1995, 1996, 1998 by David S. Issel
;                          all rights reserved.
;
;                      Written using Turbo Assembler
;
;                     To assemble use:  TASM F1-TURBO
;                         To link use:  TLINK /x/t F1-TURBO
;
; For Microsoft Macro Assembler 6.0 use:  ML /AT F1-TURBO.ASM
;
;
;               To run FormulaONE use:  F1-TURBO
;     To run FormulaONE without sound:  F1-TURBO Q
;
;  Use left and right shift keys to control your car                  __,        
;  at bottom of screen.  Try not to run into anything       _ _.--'-n_/          
;  for as long as you can.                                -(_)------(_)=         
;==========================================================================
        .MODEL  TINY
        .CODE
CODE    SEGMENT BYTE PUBLIC 'CODE'
        ASSUME  CS:CODE,DS:CODE
        ORG     0100H                   ; This will be a COM file
;--------------------------------------------------------------------------
;                       ACTUAL PROGRAM BEGINS HERE
;--------------------------------------------------------------------------
START:
        MOV     BP,AX                   ; Reset score to 0 (=MOV BP,0)
        MOV     AH,06H                  ; Clear Screen and home the cursor
        CALL    SCROLL
;--------------------------------------------------------------------------
;                             MAIN GAME LOOP
;--------------------------------------------------------------------------
GAME:
        MOV     DX,1629H                ; Load CAR loc (LINE 16H, COL 29H)
CARLOC  EQU     $-2                     ; Self modifying code (CAR loc)

        CALL    MOVEIT                  ; Move cursor to DH,DL (car loc)
;--------------------------------------------------------------------------
;  Erase the car at old screen location
;--------------------------------------------------------------------------
        MOV     AL,20H                  ; Print 5 spaces
        PUSH    AX
        OUT     61H,AL                  ;   Turn off speaker (AL=00100000b)
        MOV     BL,70H                                                ;^^
        MOV     CL,5
        INT     10H

        MOV     AX,0E0AH                ; Move cursor to next line
        INT     10H

        POP     AX                      ; Print 5 more spaces
        INT     10H
;--------------------------------------------------------------------------
;  Move to new car location based on shift key status
;--------------------------------------------------------------------------
        MOV     CL,40H                  ; Get shift key status
        MOV     ES,CX                   ;   (=MOV ES,0040H)
        MOV     AL,[BYTE PTR ES:0017H]

        TEST    AL,1                    ; Right SHIFT key pressed?
        JZ      TRYLFT                  ;    No...Try left shift
        INC     DX                      ;    Yes..move car right 1 space
TRYLFT: TEST    AL,2                    ; Left SHIFT key pressed?
        JZ      KEYEND                  ;    No...done checking keys
        DEC     DX                      ;    Yes..move car left 1 space
KEYEND: MOV     [WORD PTR DS:CARLOC],DX ; Save new car location in memory
                                        ; (That is the self-modifying part)
        PUSH    DX                      ; Save car location on stack also
;--------------------------------------------------------------------------
;  Scroll the track down one line
;--------------------------------------------------------------------------
        MOV     AX,0701H                ; Scroll screen down 1 line
        CALL    SCROLL                  ;   this also sets BH=0 and BL=2
                                        ;   and homes the cursor

        MOV     CL,40                   ; Print left side of track
LMARGN  EQU     $-1                     ;   (Pointer to Left Margin)
        INT     10H

        MOV     DX,CX                   ; Find right side of track position
        ADD     DX,26                   ;   (Starting track width = 26)
TRKWID  EQU     $-1                     ;   (Pointer to Track Width)
        MOV     CL,80
        SUB     CX,DX
        CALL    MOVEIT                  ; Move cursor to right side of track
        INT     10H                     ; Print grass on right side of track
;--------------------------------------------------------------------------
;  Print the score in the lower right corner of the screen
;--------------------------------------------------------------------------
        MOV     DX,184EH                ; Screen loc 77,25 bottom right
        CALL    MOVEIT                  ; Move cursor to score location
        MOV     AX,BP                   ; Move Score to AX
        MOV     CL,8                    ; Shift score right 8 bits
        SAR     AX,CL                   ; (This makes it hard to get to Z!)
        ADD     AX,0E00H+65             ; MOV AH,0Eh & Convert score to A-Z 
        INT     10H                     ; Print the score on the screen
;--------------------------------------------------------------------------
;  Check for a collision
;--------------------------------------------------------------------------
        POP     DX                      ; Restore car location from stack
        CALL    MOVEIT                  ; Move cursor under left front tire
        JNZ     PCAR                    ; Hit something? Yes... Print our
                                        ;   red car and exit the game
        PUSH    DX                      ; Save left tire position to stack
        ADD     DL,4                    ; Move cursor under right front tire
        CALL    MOVEIT                  ; Check to see if we hit something
        POP     DX                      ;    Restore our car position
        JNZ     PCAR                    ; Hit something? Yes... Print our
                                        ;   red car and exit the game
        PUSH    DX                      ; Save car position to stack
;--------------------------------------------------------------------------
;  No collision, go ahead and print our car (red)
;--------------------------------------------------------------------------
        CALL    PCAR                    ; Print our red car (CX=8)
;--------------------------------------------------------------------------
;  Slow game down by waiting for 3 vertical retraces and play sound effects
;--------------------------------------------------------------------------
        MOV     CL,3                    ; CX is delay invertical retraces
DELAY:  MOV     DX,03DAH                ; Video screen port
HERE:   IN      AL,DX                   ; Get current video status
        TEST    AL,8                    ; Check vertical retrace bit
        JNE     HERE                    ; Wait for 1 full vertical retrace
HERE2:                                  ; Turn on and off speaker...
        ADD     AL,[BYTE PTR DS:005DH]  ;   (Check command line for Q)
        DEC     AX                      ;   (which is for Quiet mode.)
        OUT     61H,AL                  ; while waiting for screen refresh
        IN      AL,DX
        TEST    AL,8
        JE      HERE2
        LOOP    DELAY                   ; Go wait for another until CX=0
;--------------------------------------------------------------------------
;  Keep track of our current score
;--------------------------------------------------------------------------
        INC     BP                      ; Count lines printed so far (score)
;--------------------------------------------------------------------------
;  Adjust size and placement of track
;--------------------------------------------------------------------------
        POP     DX                      ; Restore our car position fm stack
        MOV     AX,BP                   ; TEST AL=2 bytes, TEST BP=4 bytes

        TEST    AL,255                  ; Make track smaller each 256 lines
        JNZ     NOCHG                   ;   Go around if not time for change
        DEC     [BYTE PTR DS:TRKWID]    ;   Change width (Self-mod code!)
NOCHG:

        TEST    AL,9                    ; Make track wavy every so often
        JNZ     ENEMY                   ;  Time to go straight
        TEST    AL,128                  ;  Left or right?
        JZ      LEFT
        ADD     [BYTE PTR DS:LMARGN],2  ; -Move right 2 spaces (Self-mod!)
;        INC     DX                      ;    Make sure that enemy car
;        INC     DX                      ;      stays ON the track. (TAI)
LEFT:   DEC     [BYTE PTR DS:LMARGN]    ; -Move left 1 space   (Self-mod!)
;        DEC     DX                      ;    Make sure that enemy car
                                        ;      stays ON the track. (TAI)
;--------------------------------------------------------------------------
;  Draw an opponent car every 15 screen lines
;--------------------------------------------------------------------------
ENEMY:                                  ; Our car position is in DX register
        MOV     DH,0                    ; Make it into enemy position using
                                        ; True Artificial Intellegence (tm)
                                        ; ^    ^          ^  TAI :-)
        TEST    AL,15                   ; Every 15 lines print enemy car
        MOV     AX,OFFSET GAME          ;    Prepare for RET below
        PUSH    AX                      ;    Use RET as a jump to GAME loop
        JNZ     GOBACK                  ; Not time yet to print enemy car
;--------------------------------------------------------------------------
;                PRINT CAR AT SCREEN LOCATION "DX"
;
; On entry:  DH points to line, DL to column, CX to car graphic offset
;                                             (8 for red, 0 for blue car)
; On exit:  The proper car will be drawn.  Also, if we used CALL PCAR to
;           get here we will be returned into the program at that point.
;           If we used JNZ PCAR to get here we will be returned to the
;           DOS prompt (the game will end).
;--------------------------------------------------------------------------
PCAR:
        PUSH    BP                      ; Save our current score counter
        MOV     BP,OFFSET CAR2          ; Point to the car graphic
        ADD     BP,CX                   ;   Add offset to proper car
        SUB     BYTE PTR [BP+4],24      ; Print stripe on hood of car
        MOV     AX,1302H                ; Print the car to the screen
        PUSH    AX                      ;    AX may change in INT 10h call
        MOV     CL,5                    ;    Graphic is 5 characters wide
        PUSH    DS                      ;    It is located in the data seg
        POP     ES                      ;      but INT 10h needs that in ES
        INT     10H                     ; Print the first line of the car
        ADD     BYTE PTR [BP+4],24      ; Print cockpit and rear stripe
        POP     AX                      ; (=MOV AX,1302H)
        INC     DH                      ; Point to next line of the screen
        INT     10H                     ; Print the second line of the car
        POP     BP                      ; Restore current score counter
GOBACK: RET
CAR2:   
        DB      0DCH,70H,0DEH,71H,0D2H,1FH,0DDH,71H     ; Blue car graphic
        DB      0DCH,70H                                ;   Common tire
        DB      0DEH,74H,0D2H,4EH,0DDH,74H,0DCH,70H     ; Red car graphic
;--------------------------------------------------------------------------
;                     SCROLL SCREEN DOWN "AL" LINES
;                      (or if AH=6, clear screen)
;
; On entry:  AH must be 7, AL must be number of lines to scroll (1)
; On exit:   BH will be 0, BL will be 2 and we will fall through to
;            MOVEIT to home the cursor.             ^^^^^^^^^^^^
;--------------------------------------------------------------------------
SCROLL: 
        MOV     BH,70H                  ; Use Black on Gray (road color)
        XOR     CX,CX                   ;   From UL corner (=MOV CX,0)
        MOV     DX,184FH                ;   to LR corner
        INT     10H
        MOV     BX,02                   ; Set BH to 0 and BL to 2 for use
                                        ;   when we return.
        XOR     DX,DX                   ; Now, home the cursor  (=MOV DX,0)

MOVEIT: 
        MOV     AH,2                    ; Move cursor to DH,DL
        INT     10H
        MOV     AH,8                    ; Get the character under cursor
        INT     10H
        CMP     AL,20H                  ; Is it a space? (set Z flag)
        MOV     AX,09DBH                ; Set AH to 9 and AL to 0DBh for
        RET                             ;  use just after we return (don't
                                        ;  worry, Z flag will still be set)
CODE    ENDS

        END     START

3 Comments

mov r/m16, Sreg is encodeable. Would MASM have printed a different error message about the brackets if the source register had been DX instead of DS? I'm surprised you say the original error was related to that typo.
@PeterCordes : If generating 16-bit code mov [mem], ds should work, but I believe if the code was in a USE32 or FLAT segment that it may give an error (I seem to recall a peculiarity with certain versions of MASM where it would generate such an error)
8C modrm always has a memory operand size of 16-bit regardless of prefixes, in any mode. felixcloutier.com/x86/mov. Only when the destination is a register is there any confusion. (Although even then writing a 16-bit reg and leaving the upper bytes unmodified is impossible: zeroed on PPro and later, undefined on Pentium, Quark and earlier. IIRC, with a register destination it always writes the full register width even with a 66 operand-size prefix. Not 100% sure I'm remembering that right, though.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.