Hello Cemetech!

So, I was writing a program I planned on using for debugging some other programs, that would basically display the contents of HL, but in hex, and not destroy HL, which really bugged me from using BCALL DispHL

My program requires coordinates to be fed into it for display i.e. you load into (curRow) and (curCol), so that it can display in varied locations. I might rework so that it uses a register for coords... but not right now.

So, I wrote my program, DEBUG, as follows, which probably isn't very efficient but it worked... in testing:

Code:

  ORG userMem-2
  DB $BB,$6D
DispHLHex:
  PUSH HL
  LD B,4
DispHLHexLooP:            ;Caps P was a typo, did not bother fixing because I kinda liked it :)
  CALL GetPart
  CALL DispDigit
  CALL ShiftHL
  DJNZ DispHLHexLooP
  POP HL
  RET
GetPart:
  LD A,H
; A=____????
  SRL A
  SRL A
  SRL A
  SRL A ;yes this probably could be better...
; A=0000____
  RET
DispDigit:
  PUSH BC
  PUSH HL
  LD H,0
  LD L,A
  LD DE,DispDigitDAT
  ADD HL,DE
  LD A,(HL)
  BCALL PutC
  POP HL
  POP BC
  RET
ShiftHL:
  PUSH BC
  LD B,4
ShiftHLLoop:
  SLA L
  RL H    ;Shift HL so next nibble can be extracted
  DJNZ ShiftHLLoop
  POP BC
  RET
DispDigitDAT:
DB "0123456789ABCDEF"

I tested this by adding a label to the start and some input:

Code:

Aaaa: ;This was my label name just because
  LD HL,$0202
  LD (curRow),HL
  LD HL,$2486

And it worked.
However, when I tried calling from within another program, DEDEBUG, using it as a 'library'

Code:

  ORG userMem-2
  DB $BB,$6D
Start:
  LD HL,$0101
  LD (curRow),HL
  LD HL,$2486
  CALL DispHLHex
  RET

It displayed this:

Code:

7                  5
 B                  Done
  4

And I went whaaat? and tried a couple things to fix it and test further. CALLs for DispHLHex WITHIN prgmDEBUG worked. Within DEDEBUG, none worked right for me.

Even more stangely, running DEDEBUG and DEBUG consecutively resulted in strange screen glitches.

I was using Mimas as my assembler, so I wonder if there was something specific I needed to change for it to work?

I can get pictures if needed/wanted.
Programs don't have labels linked across them, if this is my understanding of what is going on:

1. Label DispHLHex exists in prgmDEBUG
2. A call is being made to DispHLHex from a program other than prgmDEBUG

Thus, a solution to your problem would be 2 options:

1. Copy the DispHLHex routine to some saferam location where it won't be destroyed, and then use that address when you make your call to DispHLHex.
2. Look up the program containing DispHLHex using _ChkFindSym or some other equavienlt, and compute the correct location of the routine.

Hope this helps! Smile And welcome to Cemetech Minxrod!
MateoConLechuga wrote:
Programs don't have labels linked across them, if this is my understanding of what is going on:

1. Label DispHLHex exists in prgmDEBUG
2. A call is being made to DispHLHex from a program other than prgmDEBUG

Thus, a solution to your problem would be 2 options:

1. Copy the DispHLHex routine to some saferam location where it won't be destroyed, and then use that address when you make your call to DispHLHex.
2. Look up the program containing DispHLHex using _ChkFindSym or some other equavienlt, and compute the correct location of the routine.

Hope this helps! Smile And welcome to Cemetech Minxrod!


Copying to a saferam area is a good idea, thanks Smile

But that's why I was using DEBUG as a library. I don't know if that is a valid thing to do but it worked at least partially in that it displayed text in hex...

Admittedly, I am not very sure on how a library works.

Thanks for the help, I will try copying to a saferam area. How would I do this though... Would I use LDI / CPI? Now I need to test it Razz

Thanks
Most libraries work by copying the actual routines to the end of a program using some crazy voodoo magic. I wouldn't recommend going this route to begin with, since it is a small routine, so the best bet would be to use a small macro to relocate your code, and then copy the relocated code to some safe area:


Code:
#macro relocate(new_location)
 #define old_location eval($)
 .org new_location
 #define g_location eval(new_location)
#endmacro

#macro endrelocate()
 #ifdef g_location
 .org $-g_location + old_location
 #undefine g_location
 #undefine old_location
 #endif
#endmacro


Then you enclose the routine like this:


Code:
_DispHLHex_Begin:
relocate(saferam)

; Place routine here

endrelocate()
_DispHLHex_End:


And then some small code to copy it to the saferam location:


Code:
ld hl,_DispHLHex_Begin
ld de,saferam
ld bc,_DispHLHex_End-_DispHLHex_Begin
ldir

Then when you want to use the routine, you can just do:


Code:
call saferam


Hope this helps, and good luck! Smile
I believe the problem is that you used ORG inside a Mimas library causing the library to be written over any program that uses the lib. Note that if you create a new Mimas program and select Type: Library/Other, there will be no header. This is because libraries are included directly in another program, which have their own header, making it unnecessary (and incorrect) to have one in the library. Here's a Mimas hex debug library I wrote:
Code:
Section: Hex (Code)

HexBlockConst:
 EX  (SP),HL
 PUSH BC
 LD   B,(HL)
 INC  HL
 LD   C,(HL)
 INC  HL
 PUSH HL
 LD   H,(HL)
 LD   L,C
θ:
 CALL Hex_HL_
 INC  HL
 DJNZ θB
 POP  HL
 INC  HL
 POP  BC
 EX  (SP),HL
 RET
HexBlock:
 PUSH BC
 PUSH HL
θ:
 CALL Hex_HL_
 INC  HL
 DJNZ θB
 POP  HL
 POP  BC
 RET
HexIY:
 PUSH IY
 JQ   θF
HexIX:
 PUSH IX
θ:
 EX   (SP),HL
 CALL HexHL
 POP  HL
 RET
Hex_HL_:
 PUSH AF
 LD   A,(HL)
 JQ   θF
HexHL:
 CALL HexH
HexL:
 PUSH AF
 LD   A,L
 JQ   θF
HexH:
 PUSH AF
 LD   A,H
 JQ   θF
Hex_DE_:
 PUSH AF
 LD   A,(DE)
 JQ   θF
HexDE:
 CALL HexD
HexE:
 PUSH AF
 LD   A,E
 JQ   θF
HexD:
 PUSH AF
 LD   A,D
 JQ   θF
Hex_BC_:
 PUSH AF
 LD   A,(BC)
 JQ   θF
HexBC:
 CALL HexB
HexC:
 PUSH AF
 LD   A,C
 JQ   θF
HexB:
 PUSH AF
 LD   A,B
 JQ   θF
HexA:
 PUSH AF
θ:
 PUSH AF
 RRCA
 RRCA
 RRCA
 RRCA
 CALL θF
 POP  AF
 CALL θF
 POP  AF
 RET
θ:
 OR   $F0
 DAA
 ADD  A,$A0
 ADC  A,$40
 BCALL PutC
 RET


Note that all of these routines restore all registers, making them perfect for debugging. HexBlockConst is especially useful because it lets you debug print some memory without even loading the address into a register. It is used like this:

Code:
 CALL HexBlockConst
 DB   NumBytes
 DW   Address



Edit: I guess I should mention how to do relocatable code in Mimas (in relation to the last post, however note that this is completely unnecessary for creating simple Mimas libraries):

Code:
DispHLHexSrc:
 RORG appBackUpScreen
DispHLHex:
; Place routine here
DispHLHexLen = PC - DispHLHex
 RORG LPC
(appBackUpScreen can be any unused saferam of sufficient size)

and to copy it (near the beginning of your program):

Code:
 LD   HL,DispHLHexSrc
 LD   DE,DispHLHex
 LD   BC,DispHLHexLen
 LDIR

and to call it:

Code:
 CALL DispHLHex
jacobly wrote:
I believe the problem is that you used ORG inside a Mimas library causing the library to be written over any program that uses the lib. Note that if you create a new Mimas program and select Type: Library/Other, there will be no header. This is because libraries are included directly in another program, which have their own header, making it unnecessary (and incorrect) to have one in the library. Here's a Mimas hex debug library I wrote:
Code:
Section: Hex (Code)

HexBlockConst:
 EX  (SP),HL
 PUSH BC
 LD   B,(HL)
 INC  HL
 LD   C,(HL)
 INC  HL
 PUSH HL
 LD   H,(HL)
 LD   L,C
θ:
 CALL Hex_HL_
 INC  HL
 DJNZ θB
 POP  HL
 INC  HL
 POP  BC
 EX  (SP),HL
 RET
HexBlock:
 PUSH BC
 PUSH HL
θ:
 CALL Hex_HL_
 INC  HL
 DJNZ θB
 POP  HL
 POP  BC
 RET
HexIY:
 PUSH IY
 JQ   θF
HexIX:
 PUSH IX
θ:
 EX   (SP),HL
 CALL HexHL
 POP  HL
 RET
Hex_HL_:
 PUSH AF
 LD   A,(HL)
 JQ   θF
HexHL:
 CALL HexH
HexL:
 PUSH AF
 LD   A,L
 JQ   θF
HexH:
 PUSH AF
 LD   A,H
 JQ   θF
Hex_DE_:
 PUSH AF
 LD   A,(DE)
 JQ   θF
HexDE:
 CALL HexD
HexE:
 PUSH AF
 LD   A,E
 JQ   θF
HexD:
 PUSH AF
 LD   A,D
 JQ   θF
Hex_BC_:
 PUSH AF
 LD   A,(BC)
 JQ   θF
HexBC:
 CALL HexB
HexC:
 PUSH AF
 LD   A,C
 JQ   θF
HexB:
 PUSH AF
 LD   A,B
 JQ   θF
HexA:
 PUSH AF
θ:
 PUSH AF
 RRCA
 RRCA
 RRCA
 RRCA
 CALL θF
 POP  AF
 CALL θF
 POP  AF
 RET
θ:
 OR   $F0
 DAA
 ADD  A,$A0
 ADC  A,$40
 BCALL PutC
 RET


Note that all of these routines restore all registers, making them perfect for debugging. HexBlockConst is especially useful because it lets you debug print some memory without even loading the address into a register. It is used like this:

Code:
 CALL HexBlockConst
 DB   NumBytes
 DW   Address



Edit: I guess I should mention how to do relocatable code in Mimas (in relation to the last post, however note that this is completely unnecessary for creating simple Mimas libraries):

Code:
DispHLHexSrc:
 RORG appBackUpScreen
DispHLHex:
; Place routine here
DispHLHexLen = PC - DispHLHex
 RORG LPC
(appBackUpScreen can be any unused saferam of sufficient size)

and to copy it (near the beginning of your program):

Code:
 LD   HL,DispHLHexSrc
 LD   DE,DispHLHex
 LD   BC,DispHLHexLen
 LDIR

and to call it:

Code:
 CALL DispHLHex

So I could use LDIR for copying, cool

Wow, this post was really informative and helpful. Didn't realize what the ORG did. I created my program as a program first for testing the test program, then testing the test program from a test program.

That was probably it, thank you for the help! I will go grab my calc and test this now Smile

What does the RORG LPC do though, in the relocatable code bit? I recognize RORG but what is the LPC for...?
Both ORG and RORG change "PC" in the sense that if you create a label then its value is relative to the last ORiGin change. In fact, the statements Label: and Label = PC are equivalent in Mimas. LPC, on the other hand, represents where in the program the code is actually being written. Now, most of the time, PC (which can also be typed $) and LPC (which can also be typed $$) are equal. This is because ORG <expr> does PC = LPC = <expr>, which means it changes both where the code is compiled to execute and where it is actually placed in the program, which for normal code is exactly what you want. The reason that programs start with ORG userMem-2 is because the operating system copies programs to userMem starting with the third byte (the first two bytes just indicate that the program is, in fact, an assembly program, and are therefore not copied). RORG <expr>, or Relative ORiGin, only does PC = <expr>, and does not change LPC. This means that the code is added to the program after the code before RORG <expr> like normal, however it is compiled to execute at a different address than it actually appears. This means that in order to run this code, you must first copy it to <expr> and then execute it by CALL/JPing to labels that appear after the RORG, causing the copy to be executed, which works because it was compiled to execute there. The statement ORG LPC means PC = LPC = LPC, effectively undoing the effect of the previous RORG. Hopefully an example will make this all clear:
Code:
 ORG  $1234
Test1:
 DW   PC
Test2:
 RORG $5678
Test3:
  DW   LPC
Test4:
Now Test1 == $1234, Test2 == $1236, Test3 == $5678, Test4 == $567A, the reference to PC evaluates to the same as Test1 and the reference to LPC evaluates to the same as Test2.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement