6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Nov 21, 2024 9:37 am

All times are UTC




Post new topic Reply to topic  [ 15 posts ] 
Author Message
PostPosted: Sat Jun 30, 2018 3:50 pm 
Offline

Joined: Mon May 25, 2015 1:12 pm
Posts: 92
Hello!

I was minding my own business writing a little basic program when I stumbled on some odd behaviour. I figured it may be a bug but I can't seem to find it in the EhBASIC source.

Code:
p$="*"
DIM q$(1)
q$(1)="*"
PRINT p$=q$(1)
 0
PRINT q$(1)=p$
 -1


So, if I have a string on the left hand side it evaluates with false being true and true being false but if I have a string array on the left hand side, it evaluates correctly. The same appears true for <> :?

Am I going mad?


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 30, 2018 5:10 pm 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
Actually ?p$=p$ fails already. a=p$=p$:?a results in 1.89739E-16. It fails only in direct mode. If you put your statements into numbered program lines the results are correct in run mode.

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 30, 2018 5:23 pm 
Offline

Joined: Mon May 25, 2015 1:12 pm
Posts: 92
Interesting clue, though I am by no means clear on how EhBASIC evaluates the expression. I've been attempting to follow LAB_EVEX, but maybe I'm barking up the wrong tree.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 30, 2018 5:54 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Strange behavior indeed. I also test it and getting the same results. In programmed mode I got:
Code:
100 P$="*"
110 DIM Q$(2)
120 Q$(1) = "*"
130 V$="+"
140 PRINTP$,Q$(1),V$
150 PRINT"P$=Q$(1) ",P$=Q$(1)
160 X=P$=Q$(1)
170 PRINTX,NOT(NOT(X))
180 PRINT"V$=Q$(1) ",V$=Q$(1)
190 X=V$=Q$(1)
200 PRINTX,NOT(NOT(X))
210 PRINT"Q$(1)=P$ ",Q$(1)=P$
220 X=Q$(1)=P$
230 PRINTX,NOT(NOT(X))
240 PRINT"Q$(1)=V$ ",Q$(1)=V$
250 X=Q$(1)=V$
260 PRINTX,NOT(NOT(X))

Ready
RUN
*             *             +
P$=Q$(1)      -1
-1            -1
V$=Q$(1)       0
 1.93215E-16   0
Q$(1)=P$      -1
-1            -1
Q$(1)=V$       0
 1.93215E-16   0

Ready


1,932E-16 isn't much but even EhBasic2.22 says:
Code:
?X=0
 0

Ready
?NOT(NOT(X))=0
-1

Ready

:o


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 01, 2018 4:48 pm 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
The string compare is at LAB_1CAE. At LAB_1CE6 the strings are actually compared if they have the same length. FAC1_1 and FAC2_2 is used to hold the indirect pointer to the strings being compared. FAC2_2 was pointing to an invalid location in direct mode. Earlier in the code the string descriptor is pulled
Code:
      LDA   FAC2_2            ; get descriptor pointer low byte
      LDY   FAC2_3            ; get descriptor pointer high byte
      JSR   LAB_22BA          ; pop (YA) descriptor off stack or from top of string space
                              ; returns with A = length, X=pointer low byte,
                              ; Y=pointer high byte
      STX   FAC2_2            ; save string pointer low byte
      STY   FAC2_3            ; save string pointer high byte
In memory the pointer to the string descriptor is off by +$100. So I went back to LAB_EVEX to see where FAC2_2 is loaded. After some more single stepping I found it is pushed onto the stack from FAC1 and then restored to FAC2. When it is pushed to the stack via LAB_1B5B FAC1 is rounded which causes the high address to be incremented by 1 if FAC1_r is > $7f. FAC1_r is not cleared when FAC1 actually contains a memory pointer. Actually it is never cleared and so I am not so sure wether it could also go wrong in run mode.
Code:
; push sign, round FAC1 and put on stack

LAB_1B5B
      PLA                     ; get return addr low byte
      STA   ut1_pl            ; save it
      INC   ut1_pl            ; increment it (was ret-1 pushed? yes!)
                              ; note! no check is made on the high byte! if the calling
                              ; routine assembles to a page edge then this all goes
                              ; horribly wrong !!!
      PLA                     ; get return addr high byte
      STA   ut1_ph            ; save it
      LDA   FAC1_s            ; get FAC1 sign (b7)
      PHA                     ; push sign

; round FAC1 and put on stack

LAB_1B66
      JSR   LAB_27BA          ; round FAC1
      LDA   FAC1_3            ; get FAC1 mantissa3
      PHA                     ; push on stack
      LDA   FAC1_2            ; get FAC1 mantissa2
      PHA                     ; push on stack
      LDA   FAC1_1            ; get FAC1 mantissa1
      PHA                     ; push on stack
      LDA   FAC1_e            ; get FAC1 exponent
      PHA                     ; push on stack
      JMP   (ut1_pl)          ; return, sort of
Either FAC1_r must be cleared when FAC1 is used as a memory pointer or LAB_27BA should check wether the data type is string or number (without breaking something else of course).

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 01, 2018 8:52 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Thank you Klaus.

Do you have any idea why the floating point accumulators are used during string compare??? Is it a space issue?


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 01, 2018 9:07 pm 
Offline

Joined: Mon May 25, 2015 1:12 pm
Posts: 92
It really confuses me when a name isn't meaningful. I'd like to know why too please?


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2018 5:31 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
While strings are saved from top of memory down in EhBASIC the pointers to the strings are saved like normal variables from the end of the program upwards. So when variables or strings are referenced the mechanism is at first identical and a variable or pointer will be loaded to the floating point accumulator. Up to this point there is no need for extra code and extra zero page locations.

Only when an operation is to be executed the extra steps are taken to reference the string location. For example a "+" operation will just use the loaded arguments and add them if they are variables. If they are strings they need to be concatenated which is a completely different operation. Only then the strings are actually copied to free space in the string area. An error will occur if the data type (string or variable) is not identical on both sides of the "+".

Of course this is not an exact description of what is happening but a simplified view of how it actually works.

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2018 6:25 am 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Ah, yes, I forget that Basic defaults to work with floats. And EhBasic does not use the % operator for integers - although it sometimes appears to distinguish between float and integer - at least it appears to me due to the speed it has compared to M$.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2018 6:56 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
GaBuZoMeu wrote:
... at least it appears to me due to the speed it has compared to M$.

I am by no stretch of the imagination an expert on either version, but the sources appear to me to do things in a superficially similar manner. Have you or anyone else had a chance to do any execution speed comparisons between them? OSI was the 32-bit float version, and therefore the most appropriate for the comparison.

Mike B.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2018 7:34 am 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
This entry was a response to the previous post. As it was quite a bit OT I moved it to http://forum.6502.org/viewtopic.php?f=1&t=5198

Arne


Last edited by GaBuZoMeu on Tue Jul 03, 2018 4:39 pm, edited 3 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2018 8:07 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
> P.S.: Sorry - this is quite a bit OT.

But a great table of benchmark results!


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2018 7:09 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
(moved to new thread: http://forum.6502.org/viewtopic.php?f=1&t=5198&p=61006)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 08, 2018 7:25 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
I have created 2 patches. They haven't been tested to the full extend and so I can't be sure that they don't break anything else for now!

Patch to fix the string compare of equal strings in direct mode returning FALSE:
Code:

; variable name set-up
; get (var), return value in FAC_1 and $ flag

LAB_1C18
      JSR   LAB_GVAR          ; get (var) address
      STA   FAC1_2            ; save address low byte in FAC1 mantissa2
      STY   FAC1_3            ; save address high byte in FAC1 mantissa3
      LDX   Dtypef            ; get data type flag, $FF=string, $00=numeric
      BMI   LAB_1C25          ; if string then return (does RTS)

LAB_1C24
      JMP   LAB_UFAC          ; unpack memory (AY) into FAC1

LAB_1C25
; *** begin patch  string pointer high byte trashed when moved to stack
; *** add
      LSR   FAC1_r            ; clear bit 7 (<$80) = do not round up
; *** end patch
      RTS



Patch to fix FALSE value stored to a variable after string compare is not exactly zero:
Code:

; perform LET

LAB_LET
      JSR   LAB_GVAR          ; get var address
      STA   Lvarpl            ; save var address low byte
      STY   Lvarph            ; save var address high byte
      LDA   #TK_EQUAL         ; get = token
      JSR   LAB_SCCA          ; scan for CHR$(A), else do syntax error then warm start
      LDA   Dtypef            ; get data type flag, $FF=string, $00=numeric
      PHA                     ; push data type flag
      JSR   LAB_EVEX          ; evaluate expression
      PLA                     ; pop data type flag
      ROL                     ; set carry if type = string
; *** begin patch  result of a string compare stores string pointer to variable
;                  but should store FAC1 (true/false value)
; *** replace
;      JSR   LAB_CKTM          ; type match check, set C for string
;      BNE   LAB_17D5          ; branch if string
; *** with
      JSR   LAB_CKTM          ; type match check, keep C (expected type)
      BCS   LAB_17D5          ; branch if string
; *** end patch

      JMP   LAB_PFAC          ; pack FAC1 into variable (Lvarpl) and return

; string LET

LAB_17D5

The patches above will eventually make it into my patched version of EhBASIC and my list of bugs supplied with the original version of EhBASIC. Now I am ready to have breakfast. :D

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 08, 2018 10:46 am 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
I need to revive some old tools. This may take some time. But then I could apply these patches and verify them as well.

Brilliant work, Klaus 8)


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 8 guests


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 post attachments in this forum

Search for:
Jump to: