1

I am trying to simulate some simple asm code using Prolog. (32 bit)

I am new in Prolog and I am stucked in some problems without any solutions.

Basically if here is the code:

...
add eax, 1
...

and I want to simulate in this way:

...
EAX is EAX - 1,
...

and swipl will generate errors like :

  Call: (7) 1 is 1-1 ? creep
 Fail: (7) 1 is 1-1 ? creep
 ....
 false

I know basically I could do like this:

EAX_temp is EAX + 1 

But how can I keep manipulate EAX in next instructions..?

Could any one give me some help..? Thank you!

lllllllllllll
  • 8,519
  • 9
  • 45
  • 80

2 Answers2

3

The "Prolog" way would be to actually maintain the state of all your registers in a term which you pass along the main predicate that runs the simulation. So, for example:

% general-purpose registers
% regs(EAX, EBX, ECX, EDX, ESI, EDI)
regs(0, 0, 0, 0, 0, 0)

But please note: this is not a predicate (hence the missing dot at the end)! This is a term, and it will be initialized to all zeros (I am assuming here):

init_regs(regs(0,0,0,0,0,0)).

So at the beginning of your program you can initialize your registers with:

main :-
    init_regs(Regs),
    step(Regs).

step(Regs) :-
    read_instruction(Instruction),
    apply_instruction(Instruction, Regs, New_regs),
    step(New_regs).

apply_instruction(add(eax, Addend),
        regs(EAX, EBX, ECX, EDX, ESI, EDI),
        regs(New_EAX, EBX, ECX, EDX, ESI, EDI)) :-
    New_EAX is EAX + Addend.

You can leave it at this, or you can have a helper predicate that provides access to the one register you need, for example:

reg_eax(reg(EAX, _, _, _, _, _), EAX).
reg_ebx(reg(_, EBX, _, _, _, _), EBX).
% and so on

And to set a register:

set_reg_eax(reg(EAX, EBX, ECX, EDX, ESI, EDI),
            New_EAX,
            reg(New_EAX, EBX, ECX, EDX, ESI, EDI)).
% and so on

which you can then use like this to define your apply_instruction/3:

apply_instruction(add(eax, Addend), Regs, New_regs) :-
    reg_eax(Regs, EAX),
    New_EAX is EAX + Addend,
    set_reg_eax(Regs, New_EAX, New_regs).

The sort of predicates, reg_eax and set_reg_eax can be automatically generated by a library, library(record) (see here), with the initial idea proposed by Richard o'Keefe in his book "The Craft of Prolog" for doing exaclty this sort of stuff. If you use the libary, you don't need to write all the access and set predicates yourself.

If you are using SWI-Prolog, however, you can also make use of Dicts; see here. This is part of the current development version of SWI-Prolog (version 7) and makes dealing with structures with named arguments much easier.

2

There are probably several good ways to do this. And the answer might further be refined by your context which is currently not clear.

One way, is you could create dynamic facts for register values:

:- dynamic(register/2).  % Fill in as needed

register(eax, 0).
register(ebx, 0).
...

add(Reg, Value) :-
    (   retract(register(Reg, OldValue))
    ->  NewValue is OldValue + Value
    ;   NewValue = Value                % If the register wasn't defined
    ),
    assertz(register(Reg, NewValue)).

Then do:

add(eax, 4).           % add eax,4

To read a register, you would just use, for example:

register(eax, EAXValue).

The main drawback of assert and retract is that they take a lot more CPU time than list manipulation. But I think they make sense for this kind of application where you have a CPU "state" that is represented by several register values.

lurker
  • 56,987
  • 9
  • 69
  • 103
  • WOW, this is a so groovy!! BTW: Could you give me some guides on how to simulate a stack using list...? I would follow this dynamic facts strategies but I don't know how... thank you! – lllllllllllll Mar 24 '14 at 00:44
  • I use only use push(Stack, Value, [Value|Stack]). should not be enough... anyway, I have to use ESP and EBP to access the stack...I am thinking to use dynamic facts, but the problem is that I don't know what data structure to use... – lllllllllllll Mar 24 '14 at 03:49
  • This is a perfectly valid approach (and you have commented on the drawbacks of your solution). The current consensus (mailing lists and such) seems to be that maintaining a state is better done in other ways. The more imperative approach is to use global variables, the more "Prolog"-y way is to keep your state in a term passed to the recursive call of your looping predicate (see my answer). –  Mar 24 '14 at 06:40
  • 1
    There are much more severe drawbacks of the `assertz/1`-based approach than just more CPU time for asserting, and which are not mentioned above: For example, you can no longer reason about and test your predicates in isolation, and it undermines the relational nature of your code: You can no longer use your predicates in all directions, and often you lose the ability to work with partially instantiated or variable arguments. None of these drawbacks are inherent when explicitly passing states around. – mat Mar 24 '14 at 07:13
  • @mat and Boris, thanks for the comments, and I see your point. If one was looking for the best approach, however, I don't think prolog would be the language of choice to simulate the execution of an assembly language program except, perhaps, if one were exploring caching decision trees. It's going to get hairy when considering memory. – lurker Mar 24 '14 at 09:50