Decoded: Rogue (1980) by Toy, Arnold, Wichman DOS version (1983) by Mel Sibony and Jon Lane Source file: ZOOM.ASM Beginner friendly, line-by-line code walkthrough by MaiZure ZOOM.ASM handles low level I/O to the monitor for cursor movement and character printing. Procedures exported to the C program and used in every file Original code: https://britzl.github.io/roguearchive/ Original code with line numbers http://www.maizure.org/projects/decoded-rogue/ZOOM_linenum.txt 1 COMMENT 2 COMMENT 3 COMMENT 4 COMMENT 5 COMMENT 6 BLANK 7 Start of the data segment - note paragraph alignment 8 Import screen dimensions 9 Inport cursor state 10 Import screen check and memory page variables 11 End of the data segment 12 BLANK 13 Start of the code segment 14 The usual segment assumptions 15 Export three functions in this file to the linked programs (the C code) 16 COMMENT 17 COMMENT 18 COMMENT 19 COMMENT 20 COMMENT 21 COMMENT 22 COMMENT 23 COMMENT 24 COMMENT 25 COMMENT 26 COMMENT 27 COMMENT 28 COMMENT 29 COMMENT 30 BLANK 31 COMMENT 32 COMMENT 33 COMMENT 34 COMMENT MOVE THE CURSOR TO A POSITION 35 Define move procedure, moves the cursor to position indicated by args 36 Store the previous stack frame 37 Start a new stack frame 38 BLANK 39 COMMENT 40 COMMENT 41 COMMENT 42 COMMENT 43 Move the row position argument from the stack in to DX 44 Move the row position argument from DX in to it's memory home 45 Move the column position argument from the stack in to DX 46 Move the column position argument from DX in to it's memory home 47 Check if cursor is on, if on ZF == 0. 48 Jump to line 57 if it is off (ZF == 1) 49 COMMENT 50 COMMENT 51 COMMENT 52 COMMENT 53 Move row position byte in to DH (column is still in DL) 54 Set up for set cursor position interrupt by putting AH = 0x02 55 Move the current video memory page number in to BH 56 Invoke BIOS interrupt 0x10 to change the cursor position 57 Exit label from handler 58 Restore the previous stack frame 59 Return to calling function 60 End of move procedure 61 BLANK 62 COMMENT 63 COMMENT 64 COMMENT 65 COMMENT PRINT CHARACTER TO THE SCREEN 66 Defines putchr procedure, prints a character to the screen 67 Store the previous stack frame 68 Start a new stack frame 69 Store the current target memory pointer (DI) 70 Store the current source memory pointer (SI) 71 BLANK 72 If the cursor is on (ON: ZF == 0, OFF: ZF == 1) 73 If cursor is on, jump to line 108 to use an interrupt to write to to the screen. Otherwise, cursor is off and we'll fallthrough for a direct write to video memory 74 BLANK 75 Move the cursor row position in to SI 76 Shift SI left by 1 (remember raw positions take up 2 bytes, one for the character and one for the attribute 77 Offset in to the row based on the position. DI now holds the target row 78 Column position in to AX 79 Shift AX left in order to find byte position for that screen data 80 Add the column offset to the current row position to find final position 81 Store the old value in ES to avoid clobber 82 Move the screen data segment in to EX 83 Put the current charcater attribute in AH 84 Put the desired character from argument 1 on the stack in to AL. AX now contains the attribute-character pair 85 Check if we need to wait for the retrace, or if it's skipped 86 If we can skip retrace check, jump to line 103 87 COMMENT 88 COMMENT 89 COMMENT 90 COMMENT 91 COMMENT 92 Store the character we want to write in to CX for now 93 Move the MMIO address of the CGA status register in to DX (0x3DA) 94 Disable interrupts while we check for retrace state 95 Read in the status byte in to AL 96 Checks the status of the first bit. 97 If the first bit is on, we're already in retrace and need to wait until the next cycle. Repeat this loop. We want retrace to be off then catch the exact moment it beings. If retrace is off, fall through 98 Reads in the the status byte again. 99 Checks to see if we're now in retrace 100 Jump back to line 98 if we're not yet in retrace 101 Restore the output bytes in to AX 102 BLANK 103 Sub to execute a memory write 104 Store the byte in AX (attrib/ch) in to the row buffer in DI 105 Restore interrupts since we're done 106 Retore the old extra segment 107 Jump to finished on line 115 108 Label for an interrupt-driven write to video memory 109 Set up BIOS syscall to write character and attribute 110 Put the character int o AL 111 Put the attribute in to BL 112 Put the video memory page in to BH 113 Set CX to 1 in order to only write one byte 114 Invoke BIOS interrupt 0x10 to write attribute/character to video memory 115 Procedure to clean up character write 116 Restore the previous source memory pointer (SI) 117 Restore the previous target memory pointer (DI) 118 Restore the previous stack frame 119 Return to calling function 120 End of putchr procedure 121 BLANK 122 COMMENT 123 COMMENT 124 COMMENT 125 COMMENT GET CHARACTER FROM THE SCREEN 126 Define curch procedure to get a character/attribute from video memory 127 Store the previous stack frame 128 Start a new stack frame 129 Store the previous destination memory pointer 130 Store the previous source memory pointer 131 BLANK 132 Check the cursor state (ON: ZF == 0, OFF: ZF == 1) 133 If the cursor is on, jump down to line 164 for the interrupt approach. Otherwise, fallthrough for a direct memory write 134 BLANK 135 Move the cursor's row value in to si 136 Shift left 1 in order to skip every other byte. Recall that a single char requires 2 bytes, so every position must be word aligned 137 Offset from the screen row by the row value to get the target row in DI 138 Move the target column in to AX 139 Shift for word-aligned offset 140 Add both the horizontal position with the current row for final position 141 Store the previous extra segment 142 Move the video data segment in to the extra segment 143 Check if we're waiting for video retrace. 144 If we don't need to wait for retrace, jump to line 159 145 COMMENT 146 COMMENT 147 COMMENT 148 COMMENT 149 COMMENT 150 Move the MMIO port of the status register in to DX 151 Disable interrupts while we wait for retrace 152 Read in the status value 153 Check if we're NOT in retrace 154 If we're in retrace, redo this check. We're looking for the exact moment the screen begins retrace. If we're not in retrace, fall through 155 Read in the status again 156 Check if we're in retrace 157 If we're still not in retrace, redo this check. Continue on retrace 158 BLANK 159 Get the character 160 Read the attribute/character from memory in to AX 161 Re-enable interrupts 162 Restore the extra segment 163 Jump to clean up on line 173 164 Set up for interrupt sequence to get characters from video memory 165 Set up AH == 0x02 to prepare to set up cursor position 166 Put the target row in to DH 167 Put the target column in to DL 168 Put the video memory page number in to BH 169 Invoke interrupt 10 to move the cursor in to position 170 Set AH to 0x08 to prep for read 171 Double check video memory page number 172 Invoke interrupt to read attribute/character in to AX. 173 Clean up our work 174 Restore the previous memory source pointer 175 Restore the previous destination memory pointer 176 Restore the previous stack frame 177 Return to calling function 178 End of curch procedure 179 BLANK 180 BLANK 181 End of code segment 182 End of program 183 EOF˙