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. Code: numcols .equ 54 numrows .equ 20 clra clrb ldx enemyval ldab #2; should be 54 resetenemies ldaa #0 staa enemyrow,x inx decb bne resetenemies ldab #2; should be 54 resetenemyval ldaa #0 staa enemyval,x inx decb 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 tsta 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 deca staa updatecount tsta bne updateenemies; loops back to the top rts ;;;;;;;;;;;;;;;;;;; checknewenemy ldaa countdown deca staa countdown tsta bne addnewenemy; if countdown is 0, then go to the addnewenemies function rts 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 rts randomnumber ldaa #7 staa randno Code: 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.
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.
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.
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.
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.
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. 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 Code: 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?
Hello, 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: Code: .model small .stack 100 .data tb1 db 'Pls enter a string, enter to finish $' tb2 db 10,13,'The characters that are not uper-case : $' xau db 80 dup(?) .code 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 std 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. Regards, Duy.