1. We have moved from vBulletin to XenForo and you are viewing the site in the middle of the move. Though the functional aspect of everything is working fine, we are still working on other changes including the new design on Xenforo.
    Dismiss Notice

Having subroutine trouble - 6800 assembly

Discussion in 'Assembly Language Programming (ALP) Forum' started by Qik, May 19, 2007.

  1. Qik

    Qik New Member

    Hi guys, i'm new to the forums but i saw some other articles and the advice given is pretty solid, so i thought i'd come here in my desperate hour of need.

    The object is to design part of a numbers game (it's for uni, i've been working for about 2 days solid on this and i'm still not getting it)

    i've got the clearing of the screen, and the basic structure along with some array usage down, but my subroutines keep pointing back to the start of my program and not to where the subroutine was called from.

    The idea is to have the program in a permenant loop that does the following:
    1. moves numbers down 1 row on the screen
    2. decides if it needs to indroduce another number based on a randomised (with limits)countdown timer and adds it into the array accordingly (the value and column position is also random)
    3. when a number reaches the bottom (row position 20) it moves it back to position 1.

    Here's the code i've got so far, i swear i've redone this like 4 or 5 times (the first attempt was so dismal i decided it best to just delete it and start afresh)

    All the comments that say 'should be 54' and whatnot i've reduced to 2 for the purposes of stepping through the program.

    numcols .equ 54
    numrows .equ 20
    	ldx enemyval
    	ldab #2; should be 54
    resetenemies	ldaa #0
    	staa enemyrow,x
    	bne resetenemies
    	ldab #2; should be 54
    resetenemyval ldaa #0
    	staa enemyval,x
    	bne resetenemyval
    	ldaa #2
    	jsr randomnumber
    	ldab randno; then multiply X 2
    	staa countdown
    engineloop jsr clearscreen; the game engine loop
    	ldaa #54
    	staa updatecount; loads 54 colums for the update subroutine
    	jsr updateenemies
    braland	ldaa #2
    	jsr checknewenemy
    	bne engineloop
    clearscreen ldaa #1
    clrscrn	ldx	 #screen	
    		stx  pcaret	;reset caret
    		ldaa #$41
    		staa 0,x
    		staa 54,x
    		staa 2,x
    		staa 3,x
    csnlp1	clr 0,x		;[x] = 0
    		inx			;x++
    		cpx	$FEE8	;screen+1000
    		bne	csnlp1	;loop
    		bra	braland		;return
    updateenemies	ldx #enemyval
    	ldaa enemyval,x
    	staa a
    	ldx #enemyrow
    	ldab enemyrow,x
    	stab y
    	bgt removing
    removing ldx #screen
    	ldaa #$30
    	staa y,x ; writes blank to position of old number
    	ldaa y
    	inca ; adds 1 to the current row, giving the next row
    	staa y
    	ldaa #a ; loads the enemyvalue
    	staa y,x; writes enemyvalue onto the correct screen position
    	ldaa y
    	cmpa #19
    	bgt movenumberup ; if y > 19, move it to the top row again ready for the next redraw
    	jmp endif
    movenumberup ldaa #0
    	staa enemyrow,x; sets the row position that was 20 back to 0 (the top row)
    endif	inx
    	ldaa updatecount; loads the counter which is 54
    	staa updatecount
    	bne updateenemies; loops back to the top
    checknewenemy	ldaa countdown
    	staa countdown
    	bne addnewenemy; if countdown is 0, then go to the addnewenemies function
    addnewenemy jsr randomnumber
    	ldaa randno; after this, divide random by 4
    	staa i
    	staa countdown; divide by 4 here
    	ldaa i
    	staa enemyval,x; stores the enemyvalue i at position i in enemyval
    	staa enemyrow,x; stores the new enemy position at row 1, position i in enemyrow
    	ldaa randno; then make randno between 1-54
    randomnumber ldaa #7
    	staa randno
    a .byte 0; current value for redrawing enemyval
    y .byte 0; current value for redrawing enemyrow	
    i .byte 0; variable for random numbers put into enemyrow and enemyval
    scrhigh .byte $FB	; high byte screen address 
    scrlow 	.byte $00	; low byte screen address 
    rowcount .byte 20	; number of rows to count
    countdown .byte 5 ;time till next enemy
    enemyval .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;array of enemy values
    enemyrow .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;array holding enemy row location
    randno .byte 0
    count .byte 0
    randcount .byte 0
    updatecount .byte 0
    screen	.equ $FB00
    pcaret	.stw $FB00
    The main problem i have is the subroutines not going to where they should be,

    I'm not here for a free homework solution, i genuinely want to learn this stuff to improve my (currently underdeveloped) skills as a programmer, i've programmed before in c++ java and also zscript (pseudocode for an online mud) but assembly is totally foreign to me. Any help would be greatly appreciated, I'll be checking in over the next day or so.

    This is all being done on an emulator with a fixed size of 54X20 chars. Apologies for the messiness of the code, it's still a jumble while i work out what i'm doing.

    Thanks in advance for any help.
    Last edited by a moderator: May 19, 2007
  2. DaWei

    DaWei New Member

    I'll propose something, but I won't actually read your code. It's far too ugly. Separate code items such as subroutines don't stand out enough to see them without a lot of searching. You also didn't place it in code tags to preserve any formatting you might have had. See the "Before you make a query" thread.

    If a subroutine call is actually going to the subroutine, but not returning to the point of the call, then you have no doubt corrupted the return address. For most microprocessors, that would be because you've clobbered it on the stack.
  3. shabbir

    shabbir Administrator Staff Member

    I have done the code formating and the url will help you do it next time.
  4. DaWei

    DaWei New Member

    Realize also that if you wanted to use 2 instead of 54, you could just change one spot, numcols equ 54, to numcols equ 2. That's a big part of the purpose of using equ. Your code still doesn't make a lot of sense. Maybe it's not all shown. When you call a subroutine, the subroutine needs to end with a return statement. Any parameters passed to the subroutine need to be removed. The return value, if any, needs to be dealt with.

    Your description of the problem is pretty good, but there are a number of issues that I don't see you addressing. How do you expect to get a number back from randno? You aren't sending one back. Is randno a library function, or have you implemented it somewhere.

    Have you programmed in a higher level language, or is assembler your first step? Have you studied the basic working of microprocessors? It's difficult to address an issue if one doesn't know whether to look for improper syntax or improper understanding of the process.
    Last edited: May 19, 2007
  5. Qik

    Qik New Member

    I have done programming in java and a little in c++ as well as a huge amount in zscript/pseudocode. Part of the course is learning how processors work but i'm lacking some understanding in certain parts.

    The code still has a number of issues, but the main thing right now is the subroutine not working properly. I'll fix up the code some more in the next couple of hours and post it back up in a more legible format.

    One question though, would i be better off use BRA instead of subroutines? I haven't really used the stack much in the code itself but i don't quite get how it works in terms of getting the RTS back to where it should be.
  6. Qik

    Qik New Member

    also, am i using the ldx and indexing for arrays properly?
  7. DaWei

    DaWei New Member

    One uses a subroutine because it's reusable. Call if from anywhere, it picks up from the point of call. When the call instruction is executed, the FOLLOWING instruction is put onto the stack and the ip is set to the address of the subroutine. When the subroutine hits the return, the address on the stack is popped into the ip, and off you go, right where you left off. The thing is, you can't screw up the stack. You can use it in the subroutine, but you have to clean it up before the return. Else, you'll pop some data or register contents of something that you've saved on the stack, and the processor will think that junk is the address to return to.

    A branch or jump is merely selecting a new path for the execution to follow. A subroutine is a timeout to do something, then pick up where you left off. You need to get that difference into your head.
  8. Qik

    Qik New Member

    thanks, that's a big help. I dont really need subroutines for this project, simple jumps and branches will do.

    I think the main problem now is the index register. Basically i'm having the value enemyrow to be an array with 54 numbers in it (default being 1,0,0,0 etc until 54 numbers fill the array) 54 because there are 54 columns. The values will range from 0-19 (there are 20 rows) so in the first array position, a value of 3 would indicate that there is an 'enemy' in row 3 in column 1.

    I think it's a syntax thing, but here is a small snippet of my index reference code.

         ldaa y
    	inca ; adds 1 to the current row, making it point to the next row
    	staa y
    	ldx #enemyrow; loads enemyrow back into x to write for the next line
    	staa enemyrow,x; writes the new enemyrow position 
    What i'm trying to do here is to load the value y into the accumulator (in this case it's 1)

    Then it increments and stores it back into y, making y = 2.

    What i think might be wrong is ldx #enemyrow. I'm assuming that loads it into the index register, and then staa enemyrow,x is storing the value in accumulator a (which is 2) into the first array posiion, in pseudocode it would be enemyrow[0].

    Is this correct?
    The second part is this statement
    a .equ 2
    y .equ 2
          ldx #screen
          ldaa a
          staa y,x
    That's with #screen loaded into the index register. i'm wanting it to write the value of a into y + current screen value. Normally the comman is staa 1,x but can i sub my value y into where 1 usually is?
  9. duynguyenvan

    duynguyenvan New Member

    Could you pls help me answer this question:
    - Please take a look at my small Assembly program that reads a tring from keyboard, then displays all the characters that are not uper-case letters in reverse order:
    .model small
    .stack 100
            tb1 db 'Pls enter a string, enter to finish $'
            tb2 db 10,13,'The characters that are not uper-case : $'
            xau db 80 dup(?)
    Main proc
            mov ax,@data
            mov ds, ax
            mov es, ax
            mov ah,9
            lea dx,tb1
            int 21h
            xor cx,cx
            lea di,xau
    nhap:        mov ah,1
            int 21h
            cmp al,13
            je thoi
            cmp al,'A'
            jb dung
            cmp al,'Z'
            ja dung
            jmp nhap
    dung:        stosb
            inc cx
            jmp nhap
    thoi:        mov ah,9
            lea dx,tb2
            int 21h
            dec di
            mov si,di
            mov ah,2
    quay:        lodsb        
            mov dl,al
            int 21h
            loop quay
            mov ah,4ch
            int 21h
    Main endp
            End main
    The code above runs very well, even though i did not use the Clear Direction Flag (cld) instruction after the instruction in red (lea di,xau)
    The string processing is still in forward direction.
    The question is that: Why?

    I appreciate your help.

  10. shabbir

    shabbir Administrator Staff Member

Share This Page