Yeah questions for the learning geek wahoo first one.
Via the Code Stream
Immediately after the CALL to the procedure, place the parameters inline with one or several .DB or .DW statements. Okay, this looks real cool, but the way to access these parameters may elude you until you realize that the return address, the top stack value, is the address of the first parameter. So you pop HL, and if off to the races (this is one of those rare exceptions to the rule of not popping without pushing something first).
Now one problem, if you put back the return address, you will return right after the CALL and the data block will be executed as code. This is solved by modifying the return address so that it points to just after the parameters. Not too difficult to do that because you will usually be at the end of the parameter list when you want to return anyway.
Program 14-4
LD HL, 0
LD (CurRow), HL
CALL Print_Out
.DB "I ain't not a dorkus", 0
RET
Print_Out:
; Get the return address/address of parameter
POP HL
_Loop:
LD A, (HL)
INC HL
OR A
JR Z, _Done
b_call(_PutC)
JR _Loop
_Done:
; Much better than POP HL \ RET
JP (HL)
You have no excuse for not understanding the code stream mechanism — you've been using it all this time! b_call(xxxx) is macro (you should know at least that much by now) that expands to
RST 28h
.DW xxxx
RST is the same as CALL, but you can clearly see that the code stream is in use here.
The code stream really is one of the more convenient ways to pass input, and code-stream parameters implement variable-length parameters quite effectively. The string parameter to Print_Out can be any length and the routine will always come off without a hitch.
For all its convenience, the code stream mechanism is not without its disadvantages. First, if you fail to pass exactly the right number of parameters in exactly the right format, the code stream becomes the crash stream. Try leaving off the zero byte, Print_Out prints garbage and returns to god-knows-where. Or you might accidently add in a second zero. Then Print_Out returns in the midst of the string and tries to execute ASCII codes as instruction opcodes. Again, this usually results in a crash (actually most characters will be 8-bit loads that may or may not be harmless).
Can any one explain this better? :/
Asm in 28 days Day 14 wrote:
Via the Code Stream
Immediately after the CALL to the procedure, place the parameters inline with one or several .DB or .DW statements. Okay, this looks real cool, but the way to access these parameters may elude you until you realize that the return address, the top stack value, is the address of the first parameter. So you pop HL, and if off to the races (this is one of those rare exceptions to the rule of not popping without pushing something first).
Now one problem, if you put back the return address, you will return right after the CALL and the data block will be executed as code. This is solved by modifying the return address so that it points to just after the parameters. Not too difficult to do that because you will usually be at the end of the parameter list when you want to return anyway.
Program 14-4
LD HL, 0
LD (CurRow), HL
CALL Print_Out
.DB "I ain't not a dorkus", 0
RET
Print_Out:
; Get the return address/address of parameter
POP HL
_Loop:
LD A, (HL)
INC HL
OR A
JR Z, _Done
b_call(_PutC)
JR _Loop
_Done:
; Much better than POP HL \ RET
JP (HL)
You have no excuse for not understanding the code stream mechanism — you've been using it all this time! b_call(xxxx) is macro (you should know at least that much by now) that expands to
RST 28h
.DW xxxx
RST is the same as CALL, but you can clearly see that the code stream is in use here.
The code stream really is one of the more convenient ways to pass input, and code-stream parameters implement variable-length parameters quite effectively. The string parameter to Print_Out can be any length and the routine will always come off without a hitch.
For all its convenience, the code stream mechanism is not without its disadvantages. First, if you fail to pass exactly the right number of parameters in exactly the right format, the code stream becomes the crash stream. Try leaving off the zero byte, Print_Out prints garbage and returns to god-knows-where. Or you might accidently add in a second zero. Then Print_Out returns in the midst of the string and tries to execute ASCII codes as instruction opcodes. Again, this usually results in a crash (actually most characters will be 8-bit loads that may or may not be harmless).
Can any one explain this better? :/