Using the Videx Videoterm with Assembly Language
- 1 Introduction
- 2 Peripheral Card Memory
- 3 Initialising the Videoterm Card
- 4 Displaying Characters
- 5 Positioning the Cursor
- 6 Direct Manipluation of Screen Memory
- 7 Summary
This article describes how to write assembler based software that utilises the Videx Videoterm 80 Column Display. The aim of the article is to provide some simple examples to describe the basics.
The manual supplied with the Videoterm product provides some example code, however, this is designed for use with DOS. The samples here will be based on ProDOS.
The examples have been tested on an Apple II+ using ProDOS 2.4.1. For the purposes of this article, it is assumed that the Videoterm Display card is located in Slot 3. The code was cross compiled using VS Code, Merlin 32 on MacOS. See the article [6502 Cross Assembly for the Apple II using MacOS], if you prefer to use Atom as your editor see the article [6502 Cross Assembly using MacOS and Atom].
Peripheral Card Memory
Scratchpad RAM (Screen Holes)
The normal Apple text mode consists of two screens (pages). These screens are mapped to the following memory locations.
Page 1 $400-$7FF Page 2 $800-$9FF
These two 1024 byte blocks support 2 screens of 40 columns x 24 rows of text (2 x 960) characters. The 64 memory locations not used in the first block (1024 - 960) are used as scratchpad RAM for peripheral cards. These locations are often refered to as Screen Holes. The Apple ][ Reference Manual (p82) and the Videterm Installation an Operation Manual (p.3-2) describes these addresses in more detail.
The addresses below show the screen hole addresses for slot 0, to determine the locations for other slots, simply add the slot number (see below). Note that the locations for slot 0 are a special case and are used as a system sratchpad rather than specifically for slot 0. They are used to store things such as the current slot in use, more on that later.
$0478 $04F8 $0578 $05F8 $0678 $06F8 $0778 $07F8
Adding the slot number (3) to above addresses gives the scratchpad ram locations for slot 3. These are shown below with a short description of what the Videoterm Display uses them for.
$047B Screen Base Address (Low) $04FB Screen Base Address (High) $057B Cursor Horozontal Position $05FB Cursor Vertical Position $067B Pascal Character Write Location $06FB First Line on the Screen $077B Power Off/Lead In Counter $07FB Video Setup Flags
I/O RAM Locations
Each peripheral card is allocated 280 bytes of RAM in the system I/O space, there is also a 2Kb common area that all cards can share.
Each slot is given 16 location for general purpose I/O starting at C080 these are shown below. The locations for slot 3 are $C0B0 - $C0BF.
Slot 1 $C090 - $C09F " 2 $C0A0 - $C0AF " 3 $C0B0 - $C0BF " 4 $C0C0 - $C0CF " 5 $C0D0 - $C0DF " 6 $C0E0 - $C0EF " 7 $C0F0 - $C0FF
Each slot is allocated memory space for 256 bytes of ROM space, the locations are shown below. The locations for slot 3 are $C300 - $C3FF.
Slot 1 $C100 - $C1FF " 2 $C200 - $C2FF " 3 $C300 - $C3FF " 4 $C400 - $C4FF " 5 $C500 - $C5FF " 6 $C600 - $C6FF " 7 $C700 - $C7FF
The memory space $C800 - $CFFF can be used by peripheral cards to hold programs or drivers etc. The whole space is available to all cards but only one card can use it at any one time.
Initialising the Videoterm Card
This code initialises the Videoterm card by switching its ROM into $C800, setting up the appropriate DOS/System locations (slot zero Screen Holes), calling the ROM entry point and clearing the screen ready for action. From this point, anything sent to COUT will appear on the 80 column display.
If the system is fitted with a Soft Switch, this can be utilised by reading or writing location $C058 (Annunciator 0).
VXSLOT EQU $7F8 ; Holds the slot number in the form $Cn (AII Ref. P.83) VXINIT LDX $C3 ; represents the slot number in the form $Cn STX VXSLOT ; store slot 3 for DOS STA $CFFF ; turn off expansion ROMS (AII Ref. P.84) STA $C300 ; accessing the memory will enable slot 3 rom LDA #$8C JMP $C300 ; init card and clear the screen LDY $C058 ; See note above regarding the Soft Switch. RTS ; all done
The Videoterm card has a couple of methods of displaying characters on the screen The first is to use the documented control sequences to update the cursor position and calling COUT to output the character. The second method, is to perform the task by directly manipulating the screen memory without affecting the cursor position. Typically, both approaches will be needed.
Positioning the Cursor
This is the simplest approach and is simply a matter of sending an appropriate control code to move the cursor. For example the following sub-routine returns the cursor to the home position (0,0) without affecting the display.
VXHOME LDA #$19 JMP COUT
This next sub-routine is similar but clears the display
VXCLS LDA #$0C JMP COUT
The following sub-routine moves the cursor forward one position and stops when column 80 is reached.
VXWIDTH EQU #80 ; Number of columns (0-79) VXCHORZ EQU $057B ; Cursor Horizontal Position VXCVERT EQU $05FB ; Cursor Vertical Position VXFORWARD LDA #$1C ; ctrl code for Forward :LOOP LDY VXCHORZ ; load the cursor horiz position CPY VXWIDTH-1 ; if at the last column then exit BEQ :END JSR COUT ; send A to COUT to move right DEX ; Y contains the number of positions to move BNE :LOOP :END RTS
The following sub-routine places the cursor at position column and row as defined by the X and Y registers.
* Cursor is positioned on the screen at row determined by Y and column determined by X * the function will not attempt to position the cursor beyond the margins VXGOTOXY LDA #$1E JSR COUT TXA CMP VXWIDTH BCC :WIDTHOK LDA VXWIDTH-1 CLC :WIDTHOK ADC #$20 ; add 32 to X and limit it to the right margin JSR COUT TYA CMP VXHEIGHT BCC :BOTTOMOK LDA VXHEIGHT-1 CLC :BOTTOMOK ADC #$20 ; add 32 to y and limit it to the bottom margin JMP COUT
The following list describes the most popular control codes for cursor movement.
- $1C Moves the cursor forward
- $08 Moves the cursor back
- $0A Moves the cursor down
- $1F Moves the cursor up
- $19 Home the cursor without affecting the display
- $0C Clear the screen
- $0D Carraige return
- $0A Line reeed
- $07 Bell
- $01 Toggles the shift
- $13 Stops and starts scrolling
- $15 Moves the cursor forward and copies a charater
- $0B Clear to end of screen
- $1D Clear to end of line
Direct Manipluation of Screen Memory
Direct manipulation of the screen is very useful for manipulating text on the screen. The ability to determine what exists at a certain screen position or display a character on the screen irrespective of the cursor position is very useful.
The 2K screen memory resides on the Videx Videoterm in 4 pages of 512 bytes. To write characters to the screen using screen memory, it is neccessary to use page relative addressing. The 512 byte page is located at address $CC00. This address is part of the [#Expansion ROM] address space and is referred to as SCREEN in the examples below.
The process of determining the address within the page, requires the following steps
- Determine the screen address for the target row and column within the 2K screen memory.
- Determine the page (0-3) that the address falls into.
- Activate the page.
- Take the Modulous 512 of the address to determine the address within the selected page.
- Determine the address within the apple memory map.
The good news is that this is not as hard as it may first seem. The following sections describe each step with pseudo code and assembler.
A Worked Example
Determine the Screen Address
The screen addreses are contiguous in that the first row on the screen is followed by the second row and so on. As each row contains 80 characters, it means that the address, within the 2K screen memory, of any character position can be found using the following formula (where X = Column and Y = Row).
SCREEN ADDRESS = X + (Y * 80)
However, it is important to recognise that with a scrolling screen, the address of the first character is somewhat dynamic. Therefore to accurately determine the address for the position at X, Y it is necessary to modify the formula to include the contents of the START address, this is stored in address $6FB (see section [#Scratchpad RAM (Screen Holes)]) and needs to be multiplied by 16 before being used.
SCREEN ADDRESS = X + (Y * 80) + ($6FB * 16)
This can be achieved in assembler reasonably easily with the help of a multiply sub-routine, however, there is a simpler way.
The Videoterm's Screen Base Address located at $478 and $4F8 (see #Scratchpad RAM (Screen Holes)) maintains the address of the current row (column 0), i.e. column 0 of the row that the cursor is on. This means that it is a simple matter to add X to the contents of this base address to find the address of the target column and row. The following assembler perfoms this task and leaves the address in the 2K range in the locations LRESULT.
LRESULT EQU $1A ; 1A/1B used to store results (low byte first) LDA VXSCREENBASEL STA LRESULT LDA VXSCREENBASEH STA LRESULT+1 TXA ; add X CLC ADC LRESULT STA LRESULT BCC :END INC LRESULT+1 :END
Determine the Page
At this point we have the screen address and need to determine the page, this is done by dividing the Address by 512.
PAGE = SCREEN ADDRESS / 512
In assembler we can do this by shifting the high byte to the right, however, when activating the correct page (see next section) the special page selection addresses are 4 bytes apart, ideally therefore, the page needs to be multiplied by 4.
This can most easily be achieved by masking bits 1 and 2 of the high byte of the adress (this gives page * 2), then shift left once to get page * 4.
LDA LRESULT+1 PHA AND #%00000110 ASL ; A now holds the page number * 4 (0-3 * 4)
Activating the Page
To activate the address, it is necessary to read the page specific address. As detailed in the section [#I/O RAM Locations], the addresses are C0B0, C0B4, COB8, COBC for the pages 0- 3 respectively. In pseudo code that would as follows.
$C0B0 + (PAGE * 4)
In assembler the following code can be used as reading the memory location is enough to activate the page.
TAX LDA $C0B0,X
Determine the Page Relative Address
Up to this point the address within the 2K screen memory has been determined. The modulous of the 2K address is used to determine the address within the 512 byte page.
PAGE ADDRESS = SCREEN ADDRESS MOD 512
In assembler this can be achieved by simply masking the seven most significant bits of the 2K address.
LDA LRESULT+1 AND #%0000001 STA LRESULT+1
Determine the Final Address
Currently we have the address within the 512 page of screen memory. By adding this address to the address in the Apple memory map where the screen memory appears i.e. $CC00, the final address can be determined.
FIANL ADDRESS = PAGE ADDRESS + $CC00
In assembler this is just a 16 bit add e.g.
LDA #$CC00 CLC ADC LRESULT STA LRESULT LDA #$CC00/256 ADC LRESULT+1 STA LRESULT+1
At this point the 16 bit value stored at LRESULT can be used to read or write to the scren at the target X (col), Y (row) position e.g. Note that X should always be zero, for these indirect operations.
LDX #$00 STA (LRESULT,X) ; write to the screen LDA (LRESULT,X) ; read from screen
Programming the Videoterm is relatively easy once a few basic concepts are understood. The control sequences provide a very simple method of moving the cursor around the screen and, depending upon the application may be sufficient.
When using direct access to the screen memory the process of calculating the paged address can seem a little complex. However, by creating some useful assembly language sub-routines perhaps based on the code above, this should be relatively easy to handle.