Getting Input

Published Friday, July 4 2014

I’m moving kind of fast here because I really want to get to the meaty parts of the code, but I want to cover how I’m getting input from the console into the system. As you might expect, it’s all about reading from the ACIA instead of writing to it.

Recall the ACIA’s addresses:

;;; ----------------------------------------------------------------------
;;; IO Addresses
;;; ----------------------------------------------------------------------

        IORW    = $8800         ; ACIA base address, R/W registers
        IOST    = IORW+1        ; ACIA status register
        IOCMD   = IORW+2        ; ACIA command register
        IOCTL   = IORW+3        ; ACIA control register

To read in a byte of data, we’ll first need to check the IOST status and see whether bit 3 is a 1. If it is, there’s data to read. On the other hand, if it’s a 0 the ACIA doesn’t have any data for us. We can just loop checking that status. This is a technique called polling, and it’s the same technique we used for writing to the ACIA.

Here’s what the code looks like:

CIN:    LDA     IOST
        AND     #$08            ; Is RX register full?
        BEQ     CIN             ; No, wait for it to fill up.
        LDA     IORW            ; Yes, load character.
        RTS                     ; and return.

Pretty straightforward. Now we can use this in conjunction with COUT to just read in keyboard input, and echo it back out to the console.

ECHO:   JSR     CIN             ; Read a character into the accumulator
        JSR     COUT            ; Echo it
        JMP     ECHO            ; And repeat

But for my monitor, I want to do something a little bit more. I want to convert all lower-case letters to upper-case, primarily so later on when I’m parsing input, I know everything will be in the same case. Turns out we can do that with a pretty simple AND mask. But we only want to do it if the character is a-z, inclusive, so we’ll need a little branching magic.

Here’s my change:

CIN:    LDA     IOST
        AND     #$08            ; Is RX register full?
        BEQ     CIN             ; No, wait for it to fill up.
        LDA     IORW            ; Yes, load character.
        ;; If the char is 'a' to 'z', inclusive, mask to upper case.
        CMP     #'a'            ; < 'a'?
        BCC     @done           ; Yes, done.
        CMP     #'{'            ; >= '{'?
        BCS     @done           ; Yes, done.
        AND     #$5f            ; No, convert lower case -> upper case,
@done:  RTS                     ; and return.

Now if the character is < ‘a’ or >= ‘{’ (which comes right after ‘z’ in ASCII land), we’ll skip the mask. But if it’s between ‘a’ and ‘z’ inclusive, we’ll apply a mask of $5F to it, which will strip off bit 5 and convert lower case to upper case.

That’s it for today. Tomorrow we’ll tackle saving input to memory and parsing it for commands.

Oh, and if you’re in the United States, have a happy and safe Independence Day!