Fill.asm error message

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Fill.asm error message

MultiplexorMan
This post was updated on .
This error message, "At line 14: Destination is M but A=24577 is an illegal memory address", is returned when my Fill program is run. However, if I step through the program everything works fine. This started after adding the clear/white section of the code. When making the screen filled/black no error was returned. I find this strange since the two sections are nearly the same.

Just to be clear this error is only returned when in "no animation" mode AND the run (>>) button is clicked. The program can be stepped through (>) in "no animation" mode. The program can also be run (>>) in "program flow" mode.

I removed my code from the post since this seems like an issue with the CPU Emulator and not the code.
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

WBahn
Administrator
MultiplexorMan wrote
This error message, "At line 14: Destination is M but A=24577 is an illegal memory address", is returned when my Fill program is run. However, if I step through the program everything works fine. This started after adding the clear/white section of the code. When making the screen filled/black no error was returned. I find this strange since the two sections are nearly the same.

Just to be clear this error is only returned when in "no animation" mode AND the run (>>) button is clicked. The program can be stepped through (>) in "no animation" mode. The program can also be run (>>) in "program flow" mode.

I removed my code from the post since this seems like an issue with the CPU Emulator and not the code.
Don't be so quick to conclude that your code is correct and that the problem is the CPU Emulator. While it is certainly possible that the problem is with the tool, this is actually pretty unlikely given how long the tool has been in use and how many thousands of people have been using it and reporting issues over that time.

Your code had a few issues with it and at least one of them can easily result in a difference in behavior between running it full speed and single stepping it. Also, there is a critical difference between your the WHITE and the BLACK section of the code that is almost guaranteed to cause a problem.

But if you are comfortable with just assuming the problem is with the tool and not your code....


Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

MultiplexorMan
Thank you for the reply. I do feel the tone was a bit uncalled for. I removed the code because it "seemed" like an issue with the tool and you're not supposed to post working code. I'm actually not comfortable with assuming I coded everything correctly and am very interested in learning more which is why I left the rest of the post up. It is helpful to know that stepping through a program can yield different results than when running a full speed.

I'm continuing to review the code and look for the errors. Thanks again for your feedback. It is very helpful to be able talk thought issues, especially since I'm a self-learner and don't have a professor or peer group to work with.
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

WBahn
Administrator
MultiplexorMan wrote
Thank you for the reply. I do feel the tone was a bit uncalled for. I removed the code because it "seemed" like an issue with the tool and you're not supposed to post working code. I'm actually not comfortable with assuming I coded everything correctly and am very interested in learning more which is why I left the rest of the post up. It is helpful to know that stepping through a program can yield different results than when running a full speed.

I'm continuing to review the code and look for the errors. Thanks again for your feedback. It is very helpful to be able talk thought issues, especially since I'm a self-learner and don't have a professor or peer group to work with.
If you repost your code I can help you understand the issues you are having. But I can't do that unless I can see your code. I looked at your code briefly and noted a few issues but when I came back when I had time to reply the code was gone so I could only make general comments about it.

The tendency to jump to the conclusion that one's code is correct and blame the tool is a natural one and one that takes some effort to resist. We've all fallen prey to it more than once. Not surprisingly, new programmers are much more susceptible than experienced programmers, but if anything when an experienced programmer concludes that the problem is the tool because they can't find any errors in their code, they can get very entrenched in the mindset. Again, we've all fallen prey to it, so it is something that getting smacked upside the head a little bit early on will save you tons of grief down the road.

In nearly 40 years of programming I think I have found a true, legitimate bug in a compiler twice. There have been several times that I thought I did -- was even sure I did -- but further efforts to prove that I did to the point that I could bring it to the company's attention eventually revealed some subtle issue with my code that I was unaware of. So at least they were very educational experiences.
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

MultiplexorMan
(LOOP)
        @SCREEN
        D=A
        @i
        M=D

        @24576
        D=M
        @WHITE
        D;JEQ

        @24576
        D=M
        @BLACK
        D;JGT

(WHITE)
       
        @i
        A=M
        M=0
        D=A+1
        @i
        M=D

        @24576
        D=M
        @WHITE
        D;JEQ

        @LOOP
        0;JMP

(BLACK)
       
        @i
        A=M
        M=-1
        D=A+1
        @i
        M=D

        @24576
        D=M
        @BLACK
        D;JGT

        @LOOP
        0;JMP
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

WBahn
Administrator
MultiplexorMan wrote
(LOOP)
        @SCREEN
        D=A
        @i
        M=D

        @24576
        D=M
        @WHITE
        D;JEQ

        @24576
        D=M
        @BLACK
        D;JGT
A problem here is that you are checking the keyboard buffer two different times with no assurance that it will be the same value both times. So a key could be down when you check it the first time (and thus not make the jump) and up when you check it the second time (and again not make the jump). In this case the consequences aren't too severe since it would flow into the (WHITE) section of the code and thus the behavior is that it will assume that no key is pressed in this situation. But in general the results could be very bad.

A good practice is to only check the keyboard status once during each pass of the loop and take the appropriate action based on that one test.

Use a template for a high level selection construct. For instance

if(test)
   if_code
else
   else_code
next_code

The three blocks of code could be located anywhere in the program (not just one after another), so perhaps

(IF_CODE)
the assembly code for the if-block
@NEXT_CODE
0; JMP
...
(ELSE_CODE)
the assembly code for the else-block
@NEXT_CODE
0; JMP
...
(NEXT_CODE)
the assembly code that follows the if() statement

Now we just have to handle the test.

assembly code to put the value of test in D
@IF_CODE
D; JNE
@ELSE_CODE
0; JMP

If the value in D is anything other than zero, this will jump to the if-block. Otherwise, if it doesn't jump, we can conclude that the value in W was zero and jump to the else-code.

If either the if-block or the else-block immediately follows the test code, then we can eliminate the unconditional jump. Since we normally think of the if-block being before the else-block, we can write it in that order.

assembly code to put the value of test in D
@ELSE_CODE
D; JEQ
(IF_CODE)
the assembly code for the if-block
@NEXT_CODE
0; JMP
(ELSE_CODE)
the assembly code for the else-block
(NEXT_CODE)
the assembly code that follows the if() statement

Notice how we used the natural flow through to eliminate all but one of the unconditional jumps.
(WHITE)
       
        @i
        A=M
        M=0
        D=A+1
        @i
        M=D

        @24576
        D=M
        @WHITE
        D;JEQ

        @LOOP
        0;JMP
What you have done here is create a loop within a loop, which is probably not what you intended.

Also, you don't prevent your code from writing to memory outside of the screen map; thus you end up with an array-bounds error.

What happens when when 'i' gets to be 24576 (i.e., right after you turn the last sixteen pixels white)? If no key is pressed, you loop back up to (WHITE) and then write a zero into 24576 (the keyboard buffer) and advance 'i' to 24577. I'm not sure how the simulator handles attempts to write to the buffer; I'd have to play around with it since I believe that this is undefined behavior. But if no key is pressed or if it overwrote whatever key code was there, it will loop back up to WHITE again and now attempt to write to 24577 which the simulator apparently is catching and throwing an error.

(BLACK)
       
        @i
        A=M
        M=-1
        D=A+1
        @i
        M=D

        @24576
        D=M
        @BLACK
        D;JGT

        @LOOP
        0;JMP
Here you have the same issue, except that if writes to the keyboard buffer are allowed you end up writing -1 to it which means it will fail the JGT test and go back up to (LOOP) at which point 'i' gets reset to the beginning of the screen buffer.

So you can see that even a tiny difference in the code can lead to very different behaviors.
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

MultiplexorMan
I'm back and have made some progress based on the feedback. This code seems stable and tests the upper and lower bounds of the screen. It seems that the next step would be to add a "fill loop" in the IF_CODE section and a "clear loop" to the ELSE_CODE section. The loops would iterate of the screen locations instead of calling them explicitly.

(LOOP)
        @24576 // Check Keyboard
        D=M
        @IF_CODE // Jump to IF_CODE if a key is being pressed
        D;JNE
        @ELSE_CODE // Jump to ELSE_CODE if NO key is being pressed
        0;JMP
(IF_CODE)
        // IF_CODE goes here
        @16384
        M=-1
        @24575
        M=-1
        @NEXT_CODE
        0;JMP
(ELSE_CODE)
        // ELSE_CODE goes here
        @16384
        M=0
        @24575
        M=0
(NEXT_CODE)
        // NEXT_CODE goes here
        @LOOP
        0;JMP
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

MultiplexorMan
(LOOP)
        @SCREEN
        D=A
        @i
        M=D
       
        @24576 // Check Keyboard
        D=M
        @IF_CODE // Jump to IF_CODE if a key is being pressed
        D;JNE
        @ELSE_CODE // Jump to ELSE_CODE if NO key is being pressed
        0;JMP
(IF_CODE)
        // IF_CODE goes here
        @i
        D=M
        @24575
        D=D-A
        @NEXT_CODE
        D;JGT
       
        @i
        A=M
        M=-1
        D=A+1
        @i
        M=D
        @IF_CODE
        0;JMP

(ELSE_CODE)
        // ELSE_CODE goes here
        @i
        D=M
        @24575
        D=D-A
        @NEXT_CODE
        D;JGT
       
        @i
        A=M
        M=0
        D=A+1
        @i
        M=D
        @ELSE_CODE
        0;JMP

(NEXT_CODE)
        // NEXT_CODE goes here
        @LOOP
        0;JMP

Here's the coded with the loops. This passed the visual and automated tests. I'm sure this code is anything but optimized. Any feedback on how to improve this code is appreciated.
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

WBahn
Administrator
In reply to this post by MultiplexorMan
I haven't worked through your code to see if it has any issues or not. If it does, then follow up with a post describing what you are seeing that is wrong. Otherwise I'll assume it is working. The rest of this post is just food for thought.

There are many ways to go about this program since the specifications are very loose -- all that is required is that if a key is held down long enough that the screen will be completely black and if no key is held down long enough that it will be completely white. How this comes about is completely unspecified.

Perhaps the simplest way is to check whether a key is pressed and, based on that, put either a 0 or a -1 into a variable. Then go into a loop that walks through the screen memory writing the value of that variable into each location (without checking the keyboard again). Once it gets through the entire screen memory, loop back up and check the keyboard again and repeat the process. The result will be that the keyboard will only get sampled once each time the entire screen is written and so it will appear that the program is not responding until it finished the current screen write -- which is fair because that is essentially what is happening. But that behavior meets spec.

Perhaps even simpler is to have a single loop that walks through the screen memory and at the beginning of each look checks to see if a key is pressed and then writes to the next screen memory location a 0 or -1 based on that check. That will make the program much more responsive (but the total time to complete an entire screen write will increase).

You can avoid having to explicitly check for the screen bounds by forcing the pointer to wrap around via bit banging.

The first screen memory location is

SCREEN + 0 = 16384 = 0100 0000 0000 0000

The last screen memory location is

SCREEN + 8191 = 24575 = 0101 1111 1111 1111

Consider what happens if, after incrementing the screen memory address, we AND it with 24575.

Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

MultiplexorMan
Thank you for the feedback! I feel like there is much to learn from the multi and fill exercises. I'm definitely going to explore that last bit, "Consider what happens if, after incrementing the screen memory address, we AND it with 24575."
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

WBahn
Administrator
MultiplexorMan wrote
Thank you for the feedback! I feel like there is much to learn from the multi and fill exercises. I'm definitely going to explore that last bit, "Consider what happens if, after incrementing the screen memory address, we AND it with 24575."
You are correct in that there is an amazing amount than can be learned even from very simple exercises like these.
Reply | Threaded
Open this post in threaded view
|

Re: Fill.asm error message

clinden
In reply to this post by WBahn
Thanks WBahn,

that was an awesome idea to simplify the code. I simply ignore the direction (allways going up) and also allways fill (never stop).

That simplified the code in total to on conditional jump and two unconditional jumps and much less dublicated code as it fills allways "up" ... so the increment and AND routing can be used allways and allways the same.

That was a serious hack...

Of cause in a multi threaded environment, that is something you do not want to do .. cause you actually wasting cycles for nothing. But that is for another story :-)

I am now down to 27 words of .hack code.

@MultiplexorMan
You actually now helped me to bring it down to 24 bytes.

I was not aware that something like M=-1 is allowed. Before I did D=0 and D=!D and then M=D to achieve to write 0xFFFF into the screenbuffer. M-1 is much quicker :) and saved some more words :-)