Sunday, March 15, 2020

Lab 4 - Pick Two pt.1

For this lab we were tasked with creating two programs from a list in 6502 assembly code. These tasks ranged in difficulty though some things were made far easier by the introduction of ROM routines which I will explain a bit later. The two tasks which out group decided on were the calculator and the colour selector. We chose these two for a couple of reasons, the largest being that we all felt most confident in out own ability to get done these two tasks over any others. So with our tasks in hand we set out to get an understanding on ROM Routines.

ROM routines are basically snippets of code saved in the memory of the chip, In order to access these you simply need to start a subroutine and the right address and it will run the subroutine as if it were code which you wrote. The Routines given to us did things which previously requited many lines of code now in just one with smart use of the various registers in order to supply input to these routines.

Now before getting to the code for the adder it is important to note that we were never able to get the blinking cursor to work properly, though the rest of the program works for sure. Now here is the full source code which will be explained bellow.

; ROM routines
define        SCINIT        $ff81 ; initialize/clear screen
define        CHRIN        $ffcf ; input character from keyboard
define        CHROUT        $ffd2 ; output character to screen
define        SCREEN        $ffed ; get screen size
define        PLOT        $fff0 ; get/set cursor coordinates

define        NUMBERA        $10;
define        NUMBERB        $20;

        jsr SCINIT
   
mainLoop:
    ldy #$00
    jsr char1
    jsr input
    jsr storeA
    ldy #$00
    jsr char2
    jsr input
    jsr storeB
    ldy #$00
    jsr charR
    jsr printAdd
    jmp mainLoop
   

input: 
    SEC
    jsr PLOT
    ldx #$15
    CLC
    jsr PLOT

   

inLoop:
    SEC
    jsr PLOT
    jsr CHRIN


charCheck:   
    cmp #$00
    beq inLoop

    cmp #$81
    beq right
   
    cmp #$83
    beq left

    cmp #$0d
    beq next

drawNum:
    cmp #$30
    bcc inLoop
   
    clc
    cmp #$3a
    bcs inLoop
   
    jsr CHROUT

    SEC
    jsr PLOT
    cpx #$17
    bne inLoop
    dex
    CLC
    jsr PLOT
    jmp inLoop


left:    cpx #$15
    beq inLoop
    jsr CHROUT
    jmp inLoop

right:    cpx #$16
    beq inLoop
    jsr CHROUT
    jmp inLoop

next:
    SEC
    jsr PLOT
    ldx #$15
    CLC
    jsr PLOT
    SEC
    jsr PLOT


    CLC
    SBC #$2F

    ASL
    ASL
    ASL
    ASL

    PHA
   

    ldx #$16
    CLC
    jsr PLOT
    SEC
    jsr PLOT

    CLC
    SBC #$2F
    PHA

    ldx #$00
    iny
    CLC
    jsr PLOT
    SEC
    jsr PLOT

    PLA
    TAX
    PLA


    rts

storeA:
    sta NUMBERA
    txa
    eor NUMBERA
    sta NUMBERA
    rts
   

storeB:
    sta NUMBERB
    txa
    eor NUMBERB
    sta NUMBERB
    rts

printAdd:
    SEC
    jsr PLOT
    ldx #$15
    CLC
    jsr PLOT
    SEC
    jsr PLOT
   
    SED
    lda NUMBERA
    adc NUMBERB
    CLD
    pha

    bcc outputAddition
    ldx #$14
    CLC
    jsr PLOT
    SEC
    jsr PLOT
    lda #$31
    jsr CHROUT
   
outputAddition:
    pla
    pha
    LSR
    LSR
    LSR
    LSR
    clc
    adc #$30
    jsr CHROUT

    pla
    and #$0F
    clc
    adc #$30
    jsr CHROUT

    SEC
    jsr PLOT
    ldx #$00
    iny
    CLC
    jsr PLOT
   
    rts

   

   
   

char1:  lda firstDigit,y
        beq charRet
        jsr CHROUT
        iny
        bne char1

char2:  lda secondDigit,y
        beq charRet
        jsr CHROUT
        iny
        bne char2

charR:  lda result,y
        beq charRet
        jsr CHROUT
        iny
        bne charR

charRet:
    rts



firstDigit:
dcb "E","N","T","E","R",32,"F","I","R","S","T",32,"D","I","G","I","T",":",32,32,32,"0","0"
dcb 00


secondDigit:
dcb "E","N","T","E","R",32,"S","E","C","O","N","D",32,"D","I","G","I","T",":",32,32,"0","0"
dcb 00

result:
dcb "R","E","S","U","L","T",":"
dcb 00


The Adder is actually quite a simple program especially thanks to ROM routines. The writing went through a few revisions before settling on the final result, this is due to poor user of subroutines in previous incarnations as well as unfamiliarity with the ROM routines. Now speaking of the ROM routines let's discuss what they are accomplishing for us here.

there are three important ROM routines to making this code as compact as it is, the first if CHROUT, this will spit out a character onto the screen and then move the cursor over one, very simple but extremely useful. It does this by simply checking the accumulator for the value and then putting it at the current cursor location, the next routine used is the compliment to CHROUT, CHRIN. As the name implies CHRIN takes a character input, this input is stored in the accumulator which means it can be used in conjunction with CHROUT to print input to the screen. The last important ROM routines we have is PLOT. This routine has two functions depending on the state of the carry flag. Either it gets the current cursor position and returns the value of the character there, or it sets the current cursor position based on what is currently in x and y.

Using these Tools the code goes through a main loop which utilizes a few subroutines in order to keep it as readable as possible. This main loop is only 12 lines but does all the work of the program vie the subroutines it calls. Let's take a closer look at it.

mainLoop:
    ldy #$00
    jsr char1
    jsr input
    jsr storeA
    ldy #$00
    jsr char2
    jsr input
    jsr storeB
    ldy #$00
    jsr charR
    jsr printAdd
    jmp mainLoop

So the first step is to set y to a known value, this allows char1 to work properly as it will print onto the screen the instructions to enter the first input and the start location is whatever y is. Next we get the first user input. This is done through quite complex code which I will explain further down. following this it stores the first number then it does it all again for the second number. After this it prints the result text followed by doing the actual addition and printing those results, this whole thing then loops allowing the program to keep taking inputs.

Now let's break down a couple of the more important components there, namely input, storeX and printAdd. input is how we get out user input and as we are simply making a calculator only certain characters are allowed we do this by limiting the values that can be read by CHRIN, if it gets anything else we simply ask it to try again. This ensures we are either getting a number, an arrow key, or the enter key. When a character is input, it will also do a check on whether or not the input field is on the second digit in order to ensure you can only write two digits. Next storeA and storeB which take the numbers provided to them and store them in different addresses, fairly simple. Lastly printAdd which does the actual adding. This subroutine switches to decimal mode before adding the two values stored in the previous subroutines together. It then checks to see if there was a carry and if there was it draws a 1 before the number, before then drawing the output of the addition.

 All of this put together and we have a working, though not perfect Adder in 6502 assembly.

No comments:

Post a Comment