Using the Videx Videoterm with Assembly Language

From GlassTTY
Revision as of 21:53, 5 February 2018 by Glasstty (talk) (Programming with the Videx Videoterm 80 Column Display)
Jump to: navigation, search

Introduction

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

ROM Locations

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

Expansion ROM

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

Displaying Characters

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

Summary

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.