Author Topic: Can someone explain Flags to me?  (Read 27776 times)

0 Members and 1 Guest are viewing this topic.

Offline lskovlun

Re: Can someone explain Flags to me?
« Reply #45 on: July 12, 2019, 09:38:27 PM »
Phil, there seems to be a problem with compiling the |= operator.
If I replace this:
Code: [Select]
(|= [gameFlags (/ flagEnum 16)] (>> $8000 (mod flagEnum 16)))
with this
Code: [Select]
(= [gameFlags (/ flagEnum 16)] (| [gameFlags (/ flagEnum 16)] (>> $8000 (mod flagEnum 16))))
then it works. For good measure, let's change Bclr as well:
Code: [Select]
(&= [gameFlags (/ flagEnum 16)] (~ (>> $8000 (mod flagEnum 16))))
becomes
Code: [Select]
(= [gameFlags (/ flagEnum 16)] (& [gameFlags (/ flagEnum 16)] (~ (>> $8000 (mod flagEnum 16)))))

Offline NilG

Re: Can someone explain Flags to me?
« Reply #46 on: July 12, 2019, 10:08:30 PM »
That does seem to make the difference here, from a few brief tests.

Offline Charles

Re: Can someone explain Flags to me?
« Reply #47 on: July 12, 2019, 10:50:10 PM »
I betcha what’s happening is the compiler is interpreting the |= as:
Code: [Select]
(= [gameFlags (/ (/ flagEnum 16) 16)] (| [gameFlags (/ flagEnum 16)] (>> $8000 (mod flagEnum 16))))

So, dividing the flag# by 16, then by 16 again.

If that’s the case, I’d expect (Bset 16) to actually set flag 0, (Bset 17) to set flag 1, etc. and (Bset 256) to set flag 16.

Offline lskovlun

Re: Can someone explain Flags to me?
« Reply #48 on: July 13, 2019, 08:33:16 AM »
No, that's not quite it. SCI Companion generates this weird code for Bset:
Code: [Select]
procedure proc_003a
; (= oldState (Btst flagEnum))
  003a:3f 01             link 1 // (var $1)
  003c:78               push1
  003d:8f 01              lsp param1
  003f:41 e6 02          call proc_0028 2
  0042:a5 00              sat temp0

; Take flagEnum and divide it by 16
  0044:8f 01              lsp param1
  0046:35 10              ldi 10
  0048:08                 div
  0049:36                push
  004a:9b 06             lsli local6

; Similarly, get the remainder
  004c:38 8000          pushi 8000 // $8000 sel_32768
  004f:8f 01              lsp param1
  0051:35 10              ldi 10
  0053:0a                 mod
; Compute $8000 >> that remainder
  0054:0c                 shr
; OR the bit in
  0055:14                  or
; but wait, wtf is this?
  0056:1a                 eq?
  0057:3a                toss
  0058:60               pprev
; Store the corrupted result back
  0059:bb 06             ssli local6
; (return oldState)
  005b:85 00              lat temp0
  005d:48                 ret
Yay stack corruption: Companion seems confused about when (/ flagEnum 16) is on the stack, and when it's not, and starts throwing away random stack values (at code offset 0057). So you are right that the code ends up storing into the wrong variable, but it is due to improper stack handling. The eq?/pprev idiom could be quite clever under the right circumstances, but I don't see how it helps here.

Offline lskovlun

Re: Can someone explain Flags to me?
« Reply #49 on: July 13, 2019, 10:41:04 AM »
Just for fun, here's what Companion decompiles its own broken Bset to:
Code: [Select]
(procedure (localproc_003a param1 &tmp temp0)
(= [gameFlags (==
(/ param1 16)
(|
[gameFlags (/ param1 16)]
(>> $8000 (mod param1 16))
)
)]
(= temp0 (localproc_0028 param1))
)
(return temp0)
)
I'm surprised it doesn't resort to assembly to explain this mess...

Offline troflip

Re: Can someone explain Flags to me?
« Reply #50 on: July 13, 2019, 01:08:59 PM »
This was fixed years ago, but the build up there is still old :-(

If someone has the repro cloned (kawa?), can they make a build?
Check out my website: http://icefallgames.com
Groundhog Day Competition

Offline Kawa

Re: Can someone explain Flags to me?
« Reply #51 on: July 13, 2019, 05:25:43 PM »
Spun up a fresh SCI0 game (since we're using Said and all that) in my March '19 copy of SCI Companion, and added the flag procedures from page 3, the ones with the return statements.

For Bset, the original code is
Code: [Select]
(procedure (Bset flagEnum  &tmp oldState)
(= oldState (Btst flagEnum))
(|= [gameFlags (/ flagEnum 16)] (>> $8000 (mod flagEnum 16)))
(return oldState)
)

This disassembles to
Code: [Select]
// EXPORTED procedure #18 (Bset)
(procedure proc_0044
  0044:3f 01             link 1 // (var $1)
  0046:78               push1
  0047:8f 01              lsp param1
  0049:41 e6 02          call proc_0032 2

  004c:a5 00              sat temp0
  004e:8f 01              lsp param1
  0050:35 10              ldi 10
  0052:08                 div
  0053:36                push
  0054:9b 35             lsli local53
  0056:38 8000          pushi 8000 // $8000 sel_32768
  0059:8f 01              lsp param1
  005b:35 10              ldi 10
  005d:0a                 mod
  005e:0c                 shr
  005f:14                  or
  0060:76               push0
  0061:1a                 eq?
  0062:35 00              ldi 0
  0064:14                  or
  0065:60               pprev
  0066:bb 35             ssli local53
  0068:85 00              lat temp0
  006a:48                 ret
)

and decompiles to
Code: [Select]
(procedure (Bset param1 &tmp temp0)
(= temp0 (Btst param1))
(= [gameFlags (|
(/ param1 16)
(== 0 (| [gameFlags temp0] (>> $8000 (mod param1 16))))
)]
(| [gameFlags temp0] (>> $8000 (mod param1 16)))
)
(return temp0)
)

However, if I copy in the SCI11 versions...
Code: [Select]
(procedure (Bset flag &tmp theWord)
(= theWord (Btest flag))
(= [gFlags  (/ flag 16)]
(| [gFlags (/ flag 16)] (>> $8000 (mod flag 16)))
)
(return theWord)
)
Code: [Select]
// EXPORTED procedure #18 (Bset)
(procedure proc_0044
  0044:3f 01             link 1 // (var $1)
  0046:78               push1
  0047:8f 01              lsp param1
  0049:41 e6 02          call proc_0032 2

  004c:a5 00              sat temp0
  004e:8f 01              lsp param1
  0050:35 10              ldi 10
  0052:08                 div
  0053:9b 35             lsli local53
  0055:38 8000          pushi 8000 // $8000 sel_32768
  0058:8f 01              lsp param1
  005a:35 10              ldi 10
  005c:0a                 mod
  005d:0c                 shr
  005e:14                  or
  005f:36                push
  0060:8f 01              lsp param1
  0062:35 10              ldi 10
  0064:08                 div
  0065:b3 35             sali local53
  0067:85 00              lat temp0
  0069:48                 ret
)
Code: [Select]
(procedure (Bset param1 &tmp temp0)
(= temp0 (Btest param1))
(= [gameFlags (/ param1 16)]
(| [gameFlags (/ param1 16)] (>> $8000 (mod param1 16)))
)
(return temp0)
)

Interesting how the decompile looks just like the original 🤔


SMF 2.0.19 | SMF © 2021, Simple Machines
Simple Audio Video Embedder

Page created in 0.035 seconds with 22 queries.