Search code examples
assemblyx86nasmbootloaderbios

Scrolling the terminal sideways (BIOS)


I am writing a bootsector game which attempts to copy the chrome dinosaur game you can play when you have no internet.

To do this, I must run from left to right until the player hits a cactus.

How do I achieve this? (How do I make the terminal scroll from right to left so that it looks like I am moving?) So instead of scrolling up and down, I need to scroll from right to left and left to right. I am in 16 bit real mode (BIOS), and I am using nasm / intel syntax.


Solution

  • In CGA-compatible text modes, the screen contents are stored in a 4000 byte buffer starting at B800:000 (unless you change the active display page, but I'll just assume you don't). Each line contains 80 characters and is stored in 160 bytes with 25 lines in total for a resolution of 80×25.

    So to scroll the screen left, you have to move the characters of the screen left by the desired number of columns and fill the right hand side of the screen with blank characters. This can be achieved easily using a series of rep movsw instructions to move the characters followed by rep stosw instructions to fill the right hand side. Assuming ds = es = b800 and assuming ds:di points to the beginning of the line, the code for shifting a single line left by c columns looks like this:

            lea     si, [di+2*c]   ; set up SI to the column that is scrolled
                                   ; into the first column of the line
            mov     cx, 80-c       ; copy all columns beginning at that column
                                   ; to the end of the row
            rep     movsw          ; scroll row to the left
            mov     cx, c          ; need to blank that many columns
            rep     stosw          ; blank remaining columns
    

    After this code sequence, DI points to the beginning of the next row. So by iterating this sequence 25 times, we can easily scroll the entire screen:

            mov     ax, 0xb800     ; screen segment
            mov     ds, ax         ; set up segments
            mov     es, ax
            xor     di, di         ; point to the beginning of the screen
            mov     dx, 25         ; process 25 lines
            mov     ax, 0x0700     ; what to scroll in (grey on black blanks)
    
    .loop:  lea     si, [di+2*c]   ; set up SI to the column that is scrolled
                                   ; into the first column of the line
            mov     cx, 80-c       ; copy all columns beginning at that column
                                   ; to the end of the row
            rep     movsw          ; scroll row to the left
            mov     cx, c          ; need to blank that many columns
            rep     stosw          ; blank remaining columns
    
            dec     dx             ; decrement loop counter
            jnz     .loop          ; loop until we're done
    

    And that's really all there is to it. Of course, if c is variable instead of a constant, the code becomes slightly more complicated. But I'm confident you'll figure it out.

    Also note that you seem to refer to the screen as the “BIOS terminal” or something like this. That's not correct. The screen is drawn by the graphics card and can in fact by changed entirely without the BIOS. The BIOS is a set of routines provided in a ROM on your computer. These include some routines to configure graphics modes and to print characters and so on. However, that's purely for convenience. You don't actually need to go through the BIOS to do any of this.