My first ASM and it doesnt do what I expect

Here you can ask questions or provide insights about how to use efficiently 6502 assembly code on the Oric.
Post Reply
User avatar
Badger
2nd Star Corporal
Posts: 20
Joined: Sat Sep 22, 2018 10:04 am
Location: Wigan, England

My first ASM and it doesnt do what I expect

Post by Badger » Wed Oct 31, 2018 11:02 pm

A first exploration of assembly and already I have questions.

I think its my brain not registering something correctly since the code below compiles and runs but does not give the results I was expecting.

The code should plot a vartical column of charaters in column 37 of the text screen with the character being dependent on which row.

I have commented the code with what I believe should be happening, but instead of a vertical column of characters I get a horizontal row.
At least the characters are correct.

Code: Select all

; In theory this should plot a veritcal column of characters A,B or C in column 37 of the text screen;
; if the row number is less than 10 then its an A
; Row number = 10 then B
; Rows greater than 10 then C

#define Y_POS	1
#define DISPLAY_ADRESS ($BB80+37+Y_POS*40)


.text

verticalchars
.(
ldy #28			;load y with number of rows to loop
loop
	sty Y_POS		; store current row number in Y_POS
	tya			; transfer y to a
	cmp #$01		;compare a with 1 to not do anything in rows 0 and 1
	bcs addblock		;not row 0 or 1 so plot something		
	jmp decrem		; is row 0 or 1 so skip adding something
addblock
	cmp #$0A		;compare a with decimal 10 which is a number between 1 and 26 
	bcs greqthan		; branch if a is greater or equal to 10
	lda #<DISPLAY_ADRESS	; get display address and write char $41 to screen (an A)
	sta write+1
  	lda #>DISPLAY_ADRESS
  	sta write+2
	lda #$41
	jmp write
greqthan
	bne gthan		; do comparison again for greater than only
	lda #<DISPLAY_ADRESS	; get display address and write char $41 to screen (a B)
	sta write+1
  	lda #>DISPLAY_ADRESS
  	sta write+2
	lda #$42
	jmp write
gthan
	lda #<DISPLAY_ADRESS	; get display address and write char $41 to screen (a C)
	 sta write+1
  	lda #>DISPLAY_ADRESS
  	sta write+2
	lda #$43
write
	sta $0123,y
	
decrem
	dey
	bne loop
	rts
.)

Any pointers or suggestions would be gratefully recieved.

Thanks in advance

Ian
flag_uk Amateurs built the Ark, Professionals built the Titanic.

christian
Officer Cadet
Posts: 57
Joined: Sun Nov 24, 2013 9:58 pm

Re: My first ASM and it doesnt do what I expect

Post by christian » Thu Nov 01, 2018 1:04 am

I think the first error is a confusion: #define define a constant.
The line

Code: Select all

#define DISPLAY_ADRESS ($BB80+37+Y_POS*40)
define a constant, not a variable.

Second, you use Y as a row index and do a sta xxxx,y in order to put a character on the row Y of the screen.
But one row is 40 characters,if you want to write a character on the next line same column you have to add 40 to the address not 1.
For the previous line same column, substract 40.

Example:
Screen base address is $BB80 (first line, column 0)
If you want to put a 'C' in first line , column 10:

Code: Select all

lda #$43
sta $bb80+00 +10
For the second line, same column:

Code: Select all

lda #$43
sta $bb80+40 +10
In your code, in all 3 blocs:

Code: Select all

	lda #<DISPLAY_ADRESS	; get display address and write char $41 to screen (an A)
	sta write+1
  	lda #>DISPLAY_ADRESS
  	sta write+2
DISPLAY_ADRESS is a constant with value: $BB80+37+Y_POS*40 => $BB80+37+40 => second line, column 37.
So the line

Code: Select all

sta $0123,y
is actually

Code: Select all

sta $BB80+37+40,y
with Y decreasing from 28 to 0, you write a character on second line, column 37+Y (actually line 3 column Y-3 if Y>3)

The working code:

Code: Select all

; In theory this should plot a veritcal column of characters A,B or C in column 37 of the text screen;
; if the row number is less than 10 then its an A
; Row number = 10 then B
; Rows greater than 10 then C

#define Y_POS	27
#define DISPLAY_ADRESS ($BB80+37+Y_POS*40)


.text

verticalchars
.(
	lda #<DISPLAY_ADRESS	; First time: $BB80+37+27*40 => Line 27, column 37
	sta write+1
	lda #>DISPLAY_ADRESS
	sta write+2

ldy #28			;load y with number of rows to loop
loop
	tya			; transfer y to a
	cmp #$01		;compare a with 1 to not do anything in rows 0 and 1
	bcs addblock		;not row 0 or 1 so plot something		
	jmp decrem		; is row 0 or 1 so skip adding something
addblock
	cmp #$0A		;compare a with decimal 10 which is a number between 1 and 26 
	bcs greqthan		; branch if a is greater or equal to 10

	lda #$41
	jmp write

greqthan
	bne gthan		; do comparison again for greater than only
	lda #$42
	jmp write

gthan
	lda #$43
write
	sta $0123 	
decrem
	sec			; Calc new display adress
	lda write+1
	sbc #40
	sta write+1
	lda write+1
	sbc #0
	sta write+1

	dey
	bne loop
	rts
.)
Some optimizations can be done.

User avatar
Dbug
Site Admin
Posts: 2724
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: My first ASM and it doesnt do what I expect

Post by Dbug » Thu Nov 01, 2018 8:08 am

Christian's answer is mostly correct, but he did make a typo in his code sample :D

Code: Select all

decrem
	sec			; Calc new display adress
	lda write+1
	sbc #40
	sta write+1                          
	lda write+1
	sbc #0
	sta write+1
The two lasts "write+1" are supposed to be "write+2".

Regarding optimizations, there are indeed many possible, like for example:
- you don't need to use "tya" so you can do "cmp", you can just do "cpy" to compare the value to Y directly.
- instead of "bcs addblock/jmp decrem/addblock" you could just "bcc decrem/addblock" (every comparison operator has an opposite)
- instead of "lda #$41/jmp write" you can just "lda #$41/bne write" (every "load" sets the zero flag, and a Bxx is faster than a JMP)

as a side note, you don't have to use hexadecimal when you could just use decimal:
- "cmp #$0A ;compare a with decimal 10 which is a number between 1 and 26" -> "cmp #10"
- "lda #$41 ; write char $41 to screen (an A)" -> lda #"A"

christian
Officer Cadet
Posts: 57
Joined: Sun Nov 24, 2013 9:58 pm

Re: My first ASM and it doesnt do what I expect

Post by christian » Thu Nov 01, 2018 2:41 pm

You're right Dbug :oops:
decrem must be:

Code: Select all

decrem
	sec			; Calc new display address
	lda write+1	; LSB
	sbc #40
	sta write+1                          
	lda write+2	; MSB
	sbc #0
	sta write+2

User avatar
Badger
2nd Star Corporal
Posts: 20
Joined: Sat Sep 22, 2018 10:04 am
Location: Wigan, England

Re: My first ASM and it doesnt do what I expect

Post by Badger » Thu Nov 01, 2018 7:16 pm

Excellent, thankyou both.

It seems I was on the right track but not quite there or as a famous comedian once said about his piano playing, "I play all the right notes, just not in the right order" :D

I wasnt expecting to produce the most optimised code at my first attempt.

The reason for using hex is just a personal thing to me. I am not used to using hex but most articles and books use it exclusively, so I am getting into the hex habbit even when I dont need to so I can recognise familiar numbers in hex.

Once again, thanks for your help :)

Ian
flag_uk Amateurs built the Ark, Professionals built the Titanic.

User avatar
Chema
Game master
Posts: 2297
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: My first ASM and it doesnt do what I expect

Post by Chema » Thu Nov 01, 2018 9:10 pm

I arrived late to help with this, but you got the best one you could get. :D

Congratulations for your first routine!

Post Reply