Как вы анализируете 4-битные фрагменты из двоичных данных?

StackOverflow https://stackoverflow.com//questions/20009905

  •  20-12-2019
  •  | 
  •  

Вопрос

Я пытаюсь понять, как я могу анализировать двоичный файл по 4 бита, если это возможно.

Например:У меня есть 2-байтовые коды, которые необходимо проанализировать, чтобы определить, какую инструкцию использовать.

#{1NNN} где первые 4 бита указывают, где какая инструкция, а NNN представляет ячейку памяти (т.е. #{1033} говорит перейти к адресу памяти #{0033}

Кажется, это легко сделать с полными байтами, но не с полубайтами:

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

потому что #{1} недействительно binary!

До сих пор я использовал гигантские операторы переключения с: #{1033} AND #{F000} = #{1000} чтобы их обработать, но задаюсь вопросом, как более зрелый реболер мог бы это сделать.

Это было полезно?

Решение

Это довольно большая запись, но она отвечает вашим потребностям и немного демонстрирует PARSE.

По сути, это работающая, хотя и простая виртуальная машина, которая использует структуру памяти, которую вы описали выше.

Я установил простой блок ОЗУ, который представляет собой настоящую программу, которую он выполняет, когда я использую PARSE с правилом грамматики эмулятора...по сути, он увеличивает адрес, а затем переходит к этому адресу, пропуская NOP.

Затем он попадает в какую-то нелегальную операцию и умирает.

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top