你如何从二进制解析4位块?

时间:2013-11-15 20:20:27

标签: parsing rebol rebol3

我试图理解如果可能的话我如何解析每4位二进制数。

例如: 我有2字节代码需要解析以确定使用哪个指令

#{1NNN}其中前4位表示哪条指令在哪里,NNN表示内存位置(即#{1033}表示跳转到内存地址#{0033}

使用完整字节执行此操作似乎很容易,但不能使用半字节:

parse #{1022} [#{10} {#22}] 

因为#{1}无效binary!

到目前为止,我已经使用了巨大的switch语句:#{1033} AND #{F000} = #{1000}来处理这些语句,但想知道一个更成熟的重新填充程序如何做到这一点。

1 个答案:

答案 0 :(得分:1)

这是一个相当大的条目,但它可以满足您的需求并展示PARSE。

这基本上是一个工作的,虽然简单的VM使用您在上面描述的内存布局。

我设置了一个简单的RAM块,它是一个实际的程序,它在我使用PARSE和模拟器语法规则时执行...基本上,它递增一个地址,然后跳转到该地址,跳过一个NOP。 / p> 然后,它会打一些非法操作并死掉。

REBOL [
    title:  "simple VM using Parse, from scratch, using no external libraries"
    author: "Maxim Olivier-Adlhoch"
    date:    2013-11-15
]

;----
; builds a bitset with all low-order bits of a byte set, 
; so only the high bits have any weight
;----
quaternary: func [value][
    bs: make bitset! 
    reduce [
        to-char (value * 16)
        '- 
        to-char ((value * 16) + 15)
    ]
]

;------
; get the 12 least significant bits of a 16 bit value
LSB-12: func [address [string! binary!] ][
    as-binary (address AND #{0FFF})
]

;------
i32-to-binary: func [
    n [integer!] 
    /rev
][
    n: load join "#{" [form to-hex to-integer n "}"]
    either rev [head reverse n][n]
]

;------
; load value at given address. (doesn't clear the opcode).
LVAL: func [addr [binary!]][
    to-integer copy/part at RAM ( (to-integer addr) + 1) 2
]


;------
; implement the opcodes which are executed by the CPU
JMP: func [addr][
    print ["jumping to " addr]
    continue: at RAM ((to-integer addr) + 1) ; 0 based address but 1 based indexing ;-)
]

INC: func [addr][
    print ["increment value at address: " addr]
    new-val: 1 + LVAL addr
    addr: 1 + to-integer addr
    bin-val: at (i32-to-binary new-val) 3
    change at RAM addr bin-val
]

DEC: func [addr][
    print ["decrement value at address: " addr]
]

NOP: func [addr][
    print "skipping Nop opcode"
]



;------
; build the bitsets to match op codes
op1: quaternary 1
op2: quaternary 2
op3: quaternary 3
op4: quaternary 4


;------
; build up our CPU emulator grammar
emulator: [ 
    some [
        [
            here:
            [ op1 (op: 'JMP)  | op2 (op: 'INC)  | op3 (op: 'DEC)  | op4 (op: 'NOP)] ; choose op code
            :here 

            copy addr 2 skip (addr: LSB-12 addr) ; get unary op data
            continue:
            (do reduce [op addr])
            :continue
        ]
        | 2 skip (
            print ["^/^/^/ERROR:  illegal opcode AT: " to-binary here " offset[" -1 + index? here "]"] ; graceful crash!
        )
    ]
]



;------
; generate a bit of binary RAM for our emulator/VM to run...

       0   2   4   6   8    ; note ... don't need comments, Rebol just skips them.
RAM: #{2002100540FF30015FFF}
RAM-blowup: { 2 002  1 005  4 0FF  3 001  5 FFF } ; just to make it easier to trace op & data


parse/all RAM emulator


print  "^/^/Yes that error is on purpose, I added the 5FFF bytes^/in the 'RAM' just to trigger it  :-)^/"

print "notice that it doesn't run the NOP (at address #0006), ^/since we used the JMP opcode to jump over it.^/"

print "also notice that the first instruction is an increment ^/for the address which is jumped (which is misaligned on 'boot')^/"

ask "press enter to continue"

输出如下:

increment value at address:  #{0002}
jumping to  #{0006}
decrement value at address:  #{0001}



ERROR:  illegal opcode AT:  #{5FFF}  offset[ 8 ]


Yes that error is on purpose, I added the 5FFF bytes
in the 'RAM' just to trigger it  :-)

notice that it doesn't run the NOP (at address #0006),
since we used the JMP opcode to jump over it.

also notice that the first instruction is an increment
for the address which is jumped (which is misaligned on 'boot')

press enter to continue