Got a copy of Rogue to work on my Altair 8800 -- here's how...

240 views
Skip to first unread message

Mark Lawler

unread,
Apr 20, 2021, 7:58:03 PM4/20/21
to Altair-Duino
It was a minor slog, but I figured it out after manually patching ROGUE.COM to change the video escape sequences from Televideo to the VT100 that comes as part of the Altair 8800 emulator pro kit.  I'm sharing what I had to do to get this to work below.  Thanks to Richard Deane for pointing out to me that the code for the uncompression looked like it was Z80 vs 8080!  That opened the door to everything!

First step was finding a version of Rogue for CP/M.  I found a copy ported/created by David Goodenough at https://britzl.github.io/roguearchive/files/rogue17cpm.zip.

Extracting the zip file yielded the rogue17.pma file that was native to a CP/M environment.  This is a self-encrypted archive compressed with  PMarc.  Note that both the file and its contents assume a Z80 vs an 8080.  You may have to briefly hold up the stop and aux 1 switches simultaneously to configure the processor to be in Zilog Z80 vs Intel 8080 emulation.

Once the Rogue files were extracted and saved on a copy of a local CP/M hard drive image, next came the task of patching the code with DDT to change all of the screen/cursor commands over from what a Televideo would expect to that the VT100 emulator included in the pro kit would want instead.  David provide instructions in what to patch in both the included rogue.doc and qterm.pat files, but not the answers for the VT100 specifically.

Here is what I patched for the VT100 emulator in the pro kit:
  • Escape character: 01CF
    • Replaced with the byte 1B
    • This is the ^[ escape code.  Where it is used I have no clue since all other sequences must also include this escape character...
  • Signon message: 01D0 - 01EF
    • 28 56 54 2D 31 30 30 29 00
    • Simply set to the string "(VT-100)"
  • Clear screen:  01F0 - 01FF
    • 1B 5B 48 1B 5B 32 4A 00
    • This is the VT100 sequence for home then clear:  ^[[H^[[2J
  • Terminal capability map:  022F
    • C3
    • This is where I tried to set start highlight and end highlight as well as clear to end of line and clear to end of screen.  At this point I believe the highlighting doesn't work yet, but the clears seem to be doing their jobs.
  • Terminal capability strings:
    • 0230H -
      • 1B 5B 37 6D 00
      • This is the sequence ^[[7m
    • 0238H
      • 1B 5B 30 6D 00
      • This is the sequence ^[[0m
    • 0260H
      • 1B 5B 30 4B
      • This is the sequence ^[[0K for clear to end of line
    • 0268H
      • 1B 5B 30 4A
      • This is the sequence ^[[0J for clear to end of screen
  • Moveto:  0200 - 022EH
    • This was the "fun" yet very educational part...  VT100s want their row and column coordinates as a DECIMAL number expressed as human readable characters (i.e. 0,0 is "0;0" and 5,20 is "5:20" or "05:20" vs the way the programming gods intended it to be where you simply take the row and column values and easily add a character value--like 32--and happily send that modified character for each coordinate location).  On the VT100 the cursor positioning sequence is ^[[RR;CCH" where RR is the human readable decimal number for the row and CC is the human readable decimal number for the column.  Now I know why everybody loved programming for monitors other than the VT100 as it cost me over 30 bytes of extra code per position call... <grin>  
    • The row/col is passed in H/L to this routine by Rogue.  You are free to not preserve any of the registers (and calling 0109H can destroy them as well) according to the instructions that were provided in Rogue.doc and QTERM.PAT.
    • First the code to receive the row and column in H/L and start the move cursor positioning sequence...
    • 0200 E5              PUSH  H               ;save H/L since 0109 can destroy it
      0201 0E 1B         MVI    C,1B
      0203 CD 09 01   CALL  0109          ;output the ^[
      0206  0E 5B        MVI    C,5B
      0208  CD 09 01  CALL  0109          ;output the [
      020B E1              POP    H                ;now what were we passed again?
      020C ED             PUSH H                ;and save it again given rogue hates registers
      020D 7C             MOV  A,H             ;pass the row in as a parameter
      020E CD 7E 02  CALL 027E           ;...and output it as a human readable decimal
      0211  0E 3B        MVI    C,3B
      0213  CD 09 01  CALL  0109          ;output the ; character between row/col      
      0216  E1             POP     H               ;what was the column again?
      0217  7D             MOV    A,L           ;pass the column as a parameter
      0218  CD 7E 02  CALL   027E        ;...and output it as human readable decimal
      021B  0E 48        MVI     C,48     
      021D  C3 09 01   JMP    0109          ;end the sequence with an H

  • So now I was out of patch memory, but obviously needed much more than this just to be able to output the row and col in human readable decimal.  With a Televideo I could have simply done an ADI with 20H and called 0109H instead of calling 027EH...  Luckily patch area 0270H - 02FFH is also provided, which I used for the conversion to human readable decimal...
    • There are two routines here.  One to do the decimal divide by 10 to break out each digit for output, the second was to handle both x and y coordinates being passed to it.  And yes the extra NOP is an artifact from editing code in place while patching in DDT...
      ; divide by 10 with tens in C and ones in A
      ; original row/col passed in A
      0270  0E 00          MVI  C,00           ;init tens to 0
      0272  FE 0A         CPI    0A              
      0274  DA 7D 02   JC      027D         ;if less than 10 left then time to return
      0277  DE 0A        SBI     0A             ;subtract 10 from our number
      0279  0C               INR   C                ;increment out tens counter
      027A C3 72 02     JMP  0272            ;loop until out of tens to count
      027D C9               RET                     ;return to caller

      ; Routine that gets passed both row or the column to convert into a 
      027E 00                NOP
      027F CD 70 02    CALL 0270          ;put tens in C and ones in the A
      0282 F5                PUSH PSW          ;save ones since it'll get nuked
      0283 79                MOV  A,C           ;let's output the tens first
      0284 C6 30          ADI    30              ;make it human readable
      0286 4F                MOV  C,A           ;tee it up for Rogue's output char function
      0287 CD 09 01     CALL  0109        ;output the tens
      028A F1                POP    PSW         ;what was the ones?
      028B C6 30           ADI    30             ;make it human readable
      028D 4F                MOV  C,A          ;tee it up for Rogue's native char out func
      028E  C3 09 01     JMP   0109          ;output that last digit


  • After verifying my code in DDT several times and then ^C-ing out of the DDT, I issued the command SAVE 89 ROUGE.COM at the CP/M prompt (QTERM.PAT says to use 45 as the number, but that is for some other program using the same patch tables, rogue.doc clearly says to use this larger value to write it all back to disk).  
I hope you find this helpful.  I have to admit I had fun crafting patch code while in DDT and then hand assembling into the correct HEX op codes.  I disassembled my patches, reviewing several times while working on it and debugging.  As you can imagine I made a tone of mistakes, but the exercise really gave me an appreciation for the binary op code construction format of the 8080 and Z80 microprocessors.  It also reminded me what life was like when coding and debugging back when dinosaurs roamed the earth...  ;) 

Thanks again to those on the forum who helped me with a quick question here and there.  Hopefully this returns the favor for somebody interested in getting this classic game running on their Altair 8800 running Z80 mode.

Best,
-Mark

Tom Wilson

unread,
Apr 21, 2021, 12:14:36 AM4/21/21
to Mark Lawler, Altair-Duino

--
You received this message because you are subscribed to the Google Groups "Altair-Duino" group.
To unsubscribe from this group and stop receiving emails from it, send an email to altair-duino...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/altair-duino/284fe30f-c410-411a-ae37-00c2a55fbdc9n%40googlegroups.com.

udo....@freenet.de

unread,
Apr 21, 2021, 2:04:33 AM4/21/21
to Altair-Duino
You do not need the conversion to decimal, the QT overlay already includes one. Here the source for the
QT overlay patch I'm using with the z80pack machines:

A>type b:qt.asm

;

; QTERM overlay for VT-100 terminal

;


; terminal name string

        ORG     01D0H

        DB      '(VT-100)',0


; now the string for clear screen

        ORG     01F0H

CLRS:   DB      1BH,'[2J'

        DB      1BH,'[1;1H',0


; moveto - this routine is called with a word in hl - h = row 


; l = column to move to, at 109 is a routine to print a char in c,

; at 10c is a routine to print a decimal number in hl (for ansi tubes)


        ORG     0200H

MOVETO: 

        PUSH    H               ; save coords

        MVI     C,1BH

        CALL    109H            ; lead in escape

        MVI     C,5BH

        CALL    109H            ; print '['

        POP     H

        PUSH    H

        MOV     L,H

        MVI     H,0

        INR     L

        CALL    10CH            ; print row in decimal

        MVI     C,3BH

        CALL    109H            ; print ';'

        POP     H

        PUSH    H

        MVI     H,0

        INR     L

        CALL    10CH            ; print column in decimal

        MVI     C,48H

        CALL    109H            ; print 'H'

        POP     H

        RET


; these next strings are used to do various screen functions. There are

; eight of them, and immediately preceding them is a flag byte. Each string

; has a bit in the byte, and if a capability is present, its bit should

; be set. This byte is an absolute necessity, as various programs use it

; to tell if various things are present.


        ORG     022FH

TCBITS: DB      11000000B       ; bits are:

                                ; 0: bright             b_brite 1

                                ; 1: dim                b_dim   2

                                ; 2: delete line        b_delln 4

                                ; 3: insert line        b_insln 8

                                ; 4: delete character   b_delch 16

                                ; 5: insert character   b_insch 32

                                ; 6: clear end line     b_cleol 64

                                ; 7: clear end screen   b_cleos 128



        ORG     0230H

BRITES: DB      '\e(\0'


        ORG     0238H

DIMS:   DB      '\e)\0'


        ORG     0240H

DLSTR:  DB      '\eR\0'


        ORG     0248H

ILSTR:  DB      '\eE\0'


        ORG     0250H

DCSTR:  DB      '\eW\0'


        ORG     0258H

ICSTR:  DB      '\eQ\0'


        ORG     0260H

CEOL:   DB      1BH,'[0K',0


        ORG     0268H

CEOS:   DB      1BH,'[0J',0


        END     100H


Mark Lawler

unread,
Apr 21, 2021, 10:15:14 AM4/21/21
to Altair-Duino
Thanks all!

Wow, if the output decimal routine at 10CH was a snake it would have bit me!  :)   The good news is others have the right answers now.   Also, computers is a hobby of continuous learning.  The day I quit learning is the day I need to quit computer science.  I still appreciate the sessions with DDT hand assembling code and getting it to work (if even a waste of time at the end of the day).  What wasn't wasted was the learning experiences both during and now after as I continue to learn even more.  

Best,
-Mark

Phillip L Harbison

unread,
Apr 21, 2021, 10:21:35 AM4/21/21
to altair...@googlegroups.com
Mark Lawler wrote:
> Also, computers is a hobby of continuous learning.  The day I
> quit learning is the day I need to quit computer science.

The day you stop learning is the day you start dying.

I've always said that! ;)

I still approach new data books with the same excitement I had when I
was a child and the Sears & Roebuck Christmas catalog arrived.

--
Phil Harbison

Charley Jones

unread,
Apr 21, 2021, 10:49:16 AM4/21/21
to Phillip L Harbison, altair...@googlegroups.com
Back in the day, the admin kept deleting copies of rogue off our term system. So I named my copy vi. Years later I was at a party with him and he stated I was the only programmer that didn’t play rogue. I was always in vi. Didn’t have the heart to tell him I was addicted to rogue.

Sent from my iPhone Xs!

> On Apr 21, 2021, at 7:21 AM, Phillip L Harbison <alv...@xavax.com> wrote:
> --
> You received this message because you are subscribed to the Google Groups "Altair-Duino" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to altair-duino...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/altair-duino/59f245cf-cfbd-3a32-e7e3-26af7ec30120%40xavax.com.

Roger Linhart

unread,
Apr 21, 2021, 11:19:36 AM4/21/21
to Charley Jones, Phillip L Harbison, Altair-Duino
Brilliant! Thanks for the chuckle!



--
Roger Linhart
Portland, OR  97230
Mobile: 541-690-8560

udo....@freenet.de

unread,
Apr 21, 2021, 1:18:55 PM4/21/21
to Altair-Duino
marksl...@gmail.com schrieb am Mittwoch, 21. April 2021 um 16:15:14 UTC+2:
Wow, if the output decimal routine at 10CH was a snake it would have bit me!  :)   The good news is others have the right answers now.   Also, computers is a hobby of continuous learning.  The day I quit learning is the day I need to quit computer science.  I still appreciate the sessions with DDT hand assembling code and getting it to work (if even a waste of time at the end of the day).  What wasn't wasted was the learning experiences both during and now after as I continue to learn even more.

I won't say it was a waste of time, at least you now can patch any binary just with DDT. The reason that I put it into
an assembler source file was, that there are several programs using the QT overlay, and I can patch them all with
one single source for any terminal and a submit file that patches the stuff together with DDT, like this:

A>type b:rogue.sub

a:xsub

a:asm qt.ddz

a:ddt rogue.com

iqt.hex

r

g0

save 89 rogue-vt.com


 
Reply all
Reply to author
Forward
0 new messages