Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Parse::RecDescent for 48bits

by bear_hwn (Acolyte)
on Apr 07, 2003 at 17:58 UTC ( [id://248689]=perlquestion: print w/replies, xml ) Need Help??

bear_hwn has asked for the wisdom of the Perl Monks concerning the following question:

i'm trying to use Parse::RecDescent to create an assembler for a 48 bit machine and i am looking for a good way past the 32 bit limit on ints. i would appreciate any pointers and/or examples. thanks.

Replies are listed 'Best First'.
Re: Parse::RecDescent for 48bits
by BrowserUk (Patriarch) on Apr 07, 2003 at 18:23 UTC

    Perl floating point representation will accurately represent integers with upto 52 or 53 bits as tye points out here (tye)Re: 64 bit Integer anyone?. Depending on exactly what operations you need to perform with the numbers, this may save you the performance hit of Math::BigInt.

    Alternatively, depending upon how the 48-bits words of the machine code are split up, it might make sense to represent them as 1x16 bit part and 1x32-bit or possibly 3x16-bits. For example, it might be that the first 16-bits define the opcode and address modes and the other 32 bits are the addresses, in which case it might be easier to manipulate these as seperate integers and only combine them when you come to convert them to binary.

    The convertion to binary could be done using pack

    # 1x16-bit + 1x32-bit big-endian to 48-word my $word48 = pack 'nN', $opcode, $operands; # 3x16-bit little-endian to 48-bit word my $word48 = pack 'vvv', $op, $src, $dst;

    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
      my starting point was to declare a var for each half of the instruction to be built and to deal with them independently. however, i have trouble with manipulations inside the grammar. (such being akin to trying to force perl to deal with values too big to be int.) e.g. the token "nop" is not recognised (and hence the grammar is incomplete) if i do:
      use Parse::RecDescent; $new_grammar = q { # perl int is limited to 32 bits { my Instruction_upper; my Instruction_lower; } program_body : instruction(s) instruction : { Instruction_upper = 0; Instruction_lower = 0; } <reject> | nop_cmd | repeat_cmd # the nop cmd command nop_cmd : nop ';' { Instruction_upper = 0; Instruction_lower = 0; } # the repeat command repeat_cmd : repeat '=' hexnum ';' { Instruction_upper = 0; Instruction_lower = (0x7c000000 | ($item[3] & 0x0FFFF) ); nop : "nop" }

        Unfortunately, unless you are using a 64-bit processor, the 'q' pack format specifier won't help you at all, and if you were using a 64-bit processor you wouldn't have the problem.

        I've never had a need for Parser::RecDescent, so your sample grammer is just so much Greek to me;) I do not understand the meaning of your statement about "doesn't recognise nop"? Hopefully, someone with knowledge of that module, maybe even TheDamian himself will happen by and help you with that.

        The main problem would appear to be trying to use 48-bit hex constants. You could use the decimal equivalents and just allow them to become floating point with no fear of lost precision, but decimal numbers are mightily inconvenient for this type of work. I'm not sure if P::RD allows you to use functions within the grammer definitions? If it does, you could maybe get away with using a function like

        sub BigHex{ my ($int,$long) = unpack'nN', pack 'H*', $_[0]; return 2**32 * $int + $long }

        This would allow you to specify your hex constants as a string parameter to BigHex() (lousy name but you can choose your own), and it would convert it and return a number:

        print BigHex 'ffffffffffff' 281474976710655

        Unfortunately, attempting to do bitwise arithmetic with numbers greater than 32-bits appears to silently truncate the operands to 32-bit and attempting string-wise bit manipulations of hex-strings won't produce numerically valid results.

        print BigHex('ffff0000ffff') | BigHex('0000ffff0000') 4294967295

        The other thought I had was using the constant module to define your constants. eg.

        use constant xFFFFFFFFFFFE => 281474976710654;

        which would be efficient as the constant subs get optimised away, but the silent truncation of values during bitwise manipulations would still be a problem, which is why I think that using two or three integers, or if p::RD can handle it, maybe an array of 2 or 3 integers is probably the only reasonable solution other than Math::BigInt and I am unsure how that would play with P::RD either.

        I'm not sure if any of this is useful to you, but maybe it will trigger some other ideas.

        Would you mind me asking what the processor is that you are aiming this at? I've never encountered a 48-bit cpu.


        Examine what is said, not who speaks.
        1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
        2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
        3) Any sufficiently advanced technology is indistinguishable from magic.
        Arthur C. Clarke.
        </code>
        btw, there is a definition for hexnum in that grammar, i just trimmed that out. (sorry.)
Re: Parse::RecDescent for 48bits
by Abigail-II (Bishop) on Apr 07, 2003 at 19:13 UTC
    There are two ways around the 32 bit limit on ints. First, there's no 32 limit on ints - if Perl notices that the result of a calculation goes beyond the 32 limit, Perl automatically promotes the integer to a float, giving you about 53 bits of accuracy. But that will give you the drawback of doing floating point arithmetic. Instead, you can build a 64bit integer Perl, assuming your compiler supports it. The drawback is a bit more memory usuage (4 bytes per integer that otherwise would not be promoted to a float).

    Abigail

Re: Parse::RecDescent for 48bits
by bart (Canon) on Apr 07, 2003 at 18:33 UTC
    Floats have a precision of 53 bits, or thereabout. 48 bits shouldn't really be a problem. You can always use int($n/2**32) and $n-2**32*int($n/2**32) to get at the higher 16, and at the lower 32 bits.

    Perhaps your machine/Perl port can handle the 'Q' type for pack. That way, you can save up to 64 bit integers, so you just have to loose 16 bits - 2 bytes, from the resulting string.

Re: Parse::RecDescent for 48bits
by tall_man (Parson) on Apr 07, 2003 at 18:06 UTC
    Have you looked at Math::BigInt? It does arbitrary-precision integers.
      yes, thanks, i had already started looking at it, but i thought there might be a cleaner/better way to solve the problem.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://248689]
Approved by jeffa
Front-paged by tall_man
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (6)
As of 2024-03-28 11:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found