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