Saturday, September 18, 2021

VAXstation 1 Software Install - Part 2 - communicating with the console


  OK, in the previous part, I did a lot of investigating and work to accomplish...nothing (that is, I figured out how to downline load  a program that had a HALT instruction as its only code, which then halted). While nothing is one of my all time favorite things, bar none, it's not what is needed here. With no OS, no debugger and no system calls available, I would need a way to print messages out on the console. A glimp in the MicroVAX1 architecture manual shows me that there are internal processor registers (^X22 and ^X23) that work like "pseudo DL11" registers, If I deposit a character in the internal register that works like the DL11 write data register, it gets printed on the console. There's another register that has a ready bit in it, so you know when it's digested a character and is ready for another one.

char:    .ascii    /A    /

ploop:
        mfpr    #^X22,r3    ;get the status of console
        tstb    r3          ;see if it's busy (just like a CSR, nicht wahr?)
        bgeq    ploop       ;if busy, come back around and check again
        mtpr    char,#^X23  ;jam longword containing byte into an internal register


  Just like for a DL11, only with processor registers instead of CSR and data registers.


   Note that you test the status byte bit 7 to see if it's busy or not, just like the CSR on a DL11. 


  From writing bytes, it's a short step to writing a string...

;+
; pstr - print string
; r0 - len to print
; r1 - addr of thing to print
;-

pstr:
        pushr    #^m<r0,r1,r2,r3>

pdoone: movzbl  (r1)+,r2        ;get next byte to print
phloop: mfpr    #^X22,r3        ;get the status of console
        tstb    r3              ;see if it's busy (just like a CSR)
        bgeq    phloop          ;if busy, come back around and check again
        mtpr    r2,#^X23        ;jam byte into an internal register
        sobgtr  r0,pdoone       ;well, that byte's done - got any more?

        popr    #^m<r0,r1,r2,r3>

        rsb

  And a routine to print a CR LF, so we can have multiple lines...

pcrlf:
        pushr    #^m<r0,r1>

        movl    #2,r0           ;we're printing two characters
        moval   crlf,r1         ;a CR and an LF
        jsb     pstr            ;do it

        popr    #^m<r0,r1>

        rsb                     ;and we're done




  It turns out that for this project I didn't need to enter anything on the console, so I didn't write routines to support that - but it too would be pretty much like programming a DL11 to read input, using internal registers ^X20 and ^X21 for status and data buffer.

  Now, I can hear what you're all thinking..."But Gleason, this will print out ASCII strings - what do you do when you need to print out binary data?" I'm glad you all asked that question. I wrote a convert binary to hex ASCII routine.

;+
; cvtbtha - convert binary to HEX ascii
; R0 - # of bytes to convert
; R1 - addr of binary bytes
; R2 - addr of ascii buffer
;-

cvtbtha:
        pushr    #^M<r0,r1,r2,r3>

hloo:
        movzbl  (r1)+,r3                ;get next byte
        movw    hextab[r3],(r2)+        ;look up two byte ASCII value in table
        sobgeq  r0,hloo                 ;any more to do?

        popr    #^m<r0,r,r2,r3>
     

  Simple, nicht wahr? But it requires a data table. My old pal Dr. Bob pointed out that a precomputed table can often significantly reduce the amount of code required. Here's the table

;+
; Hex translation table. A few bytes of table can save a lot of code...
;-

hextab::
        .ascii  /000102030405060708090A0B0C0D0E0F/
        .ascii  /101112131415161718191A1B1C1D1E1F/
        .ascii  /202122232425262728292A2B2C2D2E2F/
        .ascii  /303132333435363738393A3B3C3D3E3F/
        .ascii  /404142434445464748494A4B4C4D4E4F/
        .ascii  /505152535455565758595A5B5C5D5E5F/
        .ascii  /606162636465666768696A6B6C6D6E6F/
        .ascii  /707172737475767778797A7B7C7D7E7F/
        .ascii  /808182838485868788898A8B8C8D8E8F/
        .ascii  /909192939495969798999A9B9C9D9E9F/
        .ascii  /A0A1A2A3A4A5A6A7A8A9AAABACADAEAF/
        .ascii  /B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF/
        .ascii  /C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF/
        .ascii  /D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF/
        .ascii  /E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF/
        .ascii  /F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF/

  That gives me the basics. As an aid to coding, I wanted a way to print out a message in one line of code, without having to allocate data for a string and deal with calling the print routine. Something like

    mess    <this is a diag message>

  Mess, being short for message, not a judgement on the esthetics of the code.

  This was easy to do, although it did mix data in with the code, something I normally don't like to do. But, this whole project is nothing normal.

  Here's how I did it. I wrote a macro, mess.

        .macro  mess    string,?a,?b    ;enclose mess in <>
        pushr    #^m<r0,r1>

        brb     b               ;branch around the deposited text
a:      .ascii  /string/
        slen = . - a            ;we'll need its length
        .even
b:
        moval   a,r1            ;addr to use
        movl    #slen,r0        ;and how long
        jsb     pstr
        jsb     pcrlf

        popr    #^m,r0,r1>

        .endm   mess

pcrlf:
        pushl   r0              ;save what ya use
        pushl   r1
        movl    #2,r0           ;we're printing two characters
        moval   crlf,r1         ;a CR and an LF
        jsb     pstr            ;do it
        popl    r1              ;ok, put 'em back
        popl    r0
        rsb                     ;and we're done


  Mess saves a couple of registers, and then jumps around the following bytes where the ASCII string is stored. Then it calls pstr using the above string as arguments. After that it calls pcrlf, which prints out a carriage return and a line feed. That's needed often enough by itself that it got its own routine.


  Well, that's enough of this for now. Next part will discuss setting up the System Control Block.


No comments:

Post a Comment

Comments?