In Part 1 we looked at making an adder in 6502 assembly, this was one of the two tasks we chose for this lab, the other was a screen colour selector. The screen colour selector I personally found was a lot easier to code than the adder and took far lass code to implement. So without any delay here is the whole source code before we dive in to how it works.
; 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
jsr SCINIT
ldy #$00
initColours:
lda colours,y
beq doneInit
jsr CHROUT
iny
bne initColours
doneInit:
ldy #$00
ldx #$00
CLC
jsr PLOT
SEC
jsr PLOT
jsr flipSelect
checkIn:
SEC
jsr PLOT
jsr CHRIN
cmp #$80
beq up
cmp #$82
bne checkIn
down:
cpy #$0f
beq checkIn
jsr flipSelect
iny
jsr flipSelect
jsr drawScreen
jmp checkIn
up:
cpy #$00
beq checkIn
jsr flipSelect
dey
jsr flipSelect
jsr drawScreen
jmp checkIn
flipSelect:
ldx #$00
CLC
jsr PLOT
SEC
jsr PLOT
flipLoop:
cmp #$20
beq doneFlip
eor #$80
jsr CHROUT
SEC
jsr PLOT
clc
bcc flipLoop
doneFlip:
rts
drawScreen:
tya
pha
lda #$00 ; set pointer at $10 to $0200
sta $10
lda #$02
sta $11
pla
ldx #$06 ; max value for $11
ldy #$00 ; index
drawLoop:
sta ($10),y ; store colour
iny ; increment index
bne drawLoop ; branch until page done
inc $11 ; increment high byte of pointer
cpx $11 ; compare with max value
bne drawLoop ; continue if not done
rts
colours:
dcb "B","L","A","C","K",10
dcb "W","H","I","T","E",10
dcb "R","E","D",10
dcb "C","Y","A","N",10
dcb "P","U","R","P","L","E",10
dcb "G","R","E","E","N",10
dcb "B","L","U","E",10
dcb "Y","E","L","L","O","W",10
dcb "O","R","A","N","G","E",10
dcb "B","R","O","W","N",10
dcb "L","I","G","H","T",95,"R","E","D",10
dcb "D","A","R","K",95,"G","R","E","Y",10
dcb "G","R","E","Y",10
dcb "L","I","G","H","T",95,"G","R","E","E","N",10
dcb "L","I","G","H","T",95,"B","L","U","E",10
dcb "L","I","G","H","T",95,"G","R","E","Y",00
This code, similar to the code in pt. 1 uses a main loop as the body of the program, though this one is a bit different and also isn't named main. Though this is getting ahead of ourselves the first thing the program does is initialize the screen, it does this by going through the colour names which are stored in memory and printing them to the screen, which was fairly easy to do considering the ROM routine CHROUT can read newline properly allowing the whole thing to be one block of memory.
The main loop for this program is called checkIn, this loop is checking for an input and when it receives it updates the screen accordingly, both up and down inputs work about the same so let's just look at up. When the up arrow in pressed checkIn calls the subroutine up. This subroutine will then check if up is valid (ie: not the top of the screen) and if so it will remove the selection, then select the proper line before changing the screen colour then returning to the checkIn loop.
Now of course up and down both call their own subroutines which I will explain now. flipSelect is a pretty interesting subroutine, it simply flips the high bit of every character in whatever line is in y. which will be the currently selected line. So the first time it is called it flips it off to deselect the line, then the second time it is called it flips it on selecting the new line. The drawScreen subroutine is one we have used a lot in the course so far. It simply takes what is currently in y, as established this will be the current selected element, and it will fill the screen with that colour. We made sure to align the colours on the screen with their places in memory so their y values line up with their colour values. This results in the correct colour being displayed
putting these few simple subroutines together along with the Rom routines and we have a very compact and easy to understand bit of code which can allow you to select a colour and display it on the screen.
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.
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.
Subscribe to:
Posts (Atom)