Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Context management #99

Closed
parasyte opened this issue Aug 5, 2021 · 3 comments
Closed

Feature request: Context management #99

parasyte opened this issue Aug 5, 2021 · 3 comments

Comments

@parasyte
Copy link

parasyte commented Aug 5, 2021

There are some architectures which allow "switching" between specific processor modes. Some notable examples are ARM/Thumb and 65c816 (SNES) accumulator and index register widths. I also need this feature for an Atari Jaguar RISC assembler; the two RISC CPUs in this platform have very slightly different instruction sets. Switching between GPU and DSP mode would allow the assembler to output GPU-only or DSP-only instructions, while rejecting instructions for the opposite mode.

Here are some example assembly sources for each of the architectures mentioned above. Syntax is open to bikeshedding.

; SNES 65c816 assembler

#bits 8

; The #context directive is like a Rust enum
#context register_width {
    ax_8,
    a_16,
    x_16,
    ax_16,
}

#subruledef register_a {
    {value: u16} => {
        if register_width == a_16 || register_width == ax_16 {
            value
        } else {
            assert(value <= 0xff)
            value`8
        }
    }
}

#ruledef snes_65c816 {
    lda #{value: register_a} => 0xa9 @ value
}

; Accumulator and index registers default to 8-bit (first enum variant: ax_8)
; These instructions are 2-bytes each.
lda #0x00
; lda #0xffff ; ERROR: This should fail because the value is too large

; Set the context to enable 16-bit accumulator.
#setcontext register_width = a_16

; These instructions are 3-bytes each.
lda #0x00
lda #0xffff ; Now it works
; Atari Jaguar RISC (GPU and DSP) assembler

#bits 16

; The #context directive is like a Rust enum
#context cpu_mode {
    gpu,
    dsp,
}

#subruledef gpr {
    r{reg: u5} => reg
}

#ruledef jaguar_risc {
    ; These instructions exist on both architectures
    add {reg1: gpr}, {reg2: gpr} => 0b000000 @ reg1 @ reg2
    nop                          => 0b111001 @ 0[9:0]
    {}                           => {
        if cpu_mode == gpu {
            ; These instructions only exist on the GPU
            pack    {reg2: gpr}          => 0b111111 @ 0b00000 @ reg2
        } else {
            ; These instructions only exist on the DSP
            addqmod {n: u5}, {reg2: gpr} => 0b111111 @ n @ reg2
        }
    }
}

; Most instructions work on either CPU mode (default to GPU; first enum variant)
add r0, r1
nop

; Instruction matching is based on the CPU mode
pack r1 ; Works in GPU mode
; addqmod 7, r1 ; ERROR: Only works in DSP mode

; Set the context to enable DSP instructions
#setcontext cpu_mode = dsp

; pack r1 ; ERROR: Only works in GPU mode
addqmod 7, r1 ; Works in DSP mode

The ARM/Thumb example is far too complex to sketch here. It's probably easiest for asm files to just #include the ruleset for the CPU mode (ARM or Thumb) that will be accepted for the whole compilation unit.

@ProxyPlayerHD
Copy link

i sort of already asked for this kind of mode switching in issue #76
though i only used the 65816 as example for CPUs that do this kind of thing.

@parasyte
Copy link
Author

parasyte commented Aug 8, 2021

I tried to find an existing issue to avoid creating a dupe. Just didn’t see it. Thanks!

@parasyte parasyte closed this as completed Aug 8, 2021
@hlorenzi
Copy link
Owner

hlorenzi commented Aug 8, 2021

@parasyte Please bring your post over to the other issue, then! I think it's got some useful ideas for implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants