Skip to content
wasmテキストフォーマットのプリプロセッサ拡張
JavaScript WebAssembly Vim script Makefile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.vscode
bin
examples/psg-emulator
lib
tests
.gitignore
LICENSE
README.md
Session.vim
build
index.js
makefile
mwasm-parser.js
out.txt
package-lock.json
package.json
rollup.config.js
static-server.js
test.wasm

README.md

mwasm

概要

mwasm用のプリプロセッサです。定数式はJavaScriptの構文を採用し、アセンブラでいうところのマクロ機能の一部を実現します。

{@
  $.GETA_BITS = 24;
  $.EMU2149_VOL_YM2149 = 0;
  $.EMU2149_VOL_AY_3_8910 = 1;
  $.EMU2149_VOL_DEFAULT  =  $.EMU2149_VOL_AY_3_8910;
  $.SHIFT_BITS = 1 << $.GETA_BITS;
  $.SHIFT_BITS_MASK = (1 << $.GETA_BITS) - 1;
}

{@struct PSG
i32 regmsk[16] = [
    0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0x3f,
    0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff
];
    (;; Volume Table ;;)
    i32 voltbl_[64] = [ 0 , 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09,
   0x0B, 0x0D, 0x0F, 0x12, 0x16, 0x1A, 0x1F, 0x25, 0x2D, 0x35, 0x3F, 0x4C,
   0x5A, 0x6A, 0x7F, 0x97, 0xB4, 0xD6, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x01,
   0x02, 0x02, 0x03, 0x03, 0x05, 0x05, 0x07, 0x07, 0x0B, 0x0B, 0x0F, 0x0F,
   0x16, 0x16, 0x1F, 0x1F, 0x2D, 0x2D, 0x3F, 0x3F, 0x5A, 0x5A, 0x7F, 0x7F,
   0xB4, 0xB4, 0xFF, 0xFF];
    i32 reg[16];
    i32 voltbl;
    i32 out;

    i32 clk, rate, base_incr, quality;

    i32 count[3];
    i32 volume[3];
    i32 freq[3];
    i32 edge[3];
    i32 tmask[3];
    i32 nmask[3];
    i32 mask;

    i32 base_count;

    i32 env_volume;
    i32 env_ptr;
    i32 env_face;

    i32 env_continue;
    i32 env_attack;
    i32 env_alternate;
    i32 env_hold;
    i32 env_pause;
    i32 env_reset;

    i32 env_freq;
    i32 env_count;

    i32 noise_seed;
    i32 noise_count;
    i32 noise_freq;

    (;; rate converter ;;)
    i32 realstep;
    i32 psgtime;
    i32 psgstep;

    (;; I/O Ctrl ;;)
    i32 adr;

    (;; output of channels ;;)
    i32 ch_out[3];


}


(module
  (export "setQuality" (func $set_quality))
  (export "setRate" (func $set_rate))
  (export "init" (func $init))
  (export "setVolumeMode" (func $set_volume_mode))
  (export "setMask" (func $set_mask))
  (export "toggleMask" (func $toggle_mask))
  (export "readIo" (func $read_io))
  (export "readReg" (func $read_reg))
  (export "writeIo" (func $write_io))
  (export "updateOutput" (func $update_output))
  (export "mixOutput" (func $mix_output))
  (export "calc" (func $calc))
  (export "reset" (func $reset))
  (export "writeReg" (func $write_reg))
  (export "memory" (memory $memory))
  (memory $memory 1 )
{@map
  PSG psg;
  f32 OutputBuffer[128];
}
  (func $internal_refresh
    (if
      ;; condition
      (i32.load (&psg.quality;))
      (then 
        (i32.store (&psg.base_incr;) (i32.const {$ 1 << $.GETA_BITS}))
        (i32.store 
          (&psg.realstep;)
          (i32.div_u 
            (i32.const {$ 1 << 31})
            (i32.load (&psg.rate;))
          ) 
        )
        (i32.store
          (&psg.psgstep;)
          (i32.div_u
            (i32.const {$ 1 << 31})
            (i32.shr_u (i32.load (&psg.clk;)) (i32.const 4))
          )
        )
        (i32.store (&psg.psgtime;) (i32.const 0))
      )
      (else
        (i32.store
          (&psg.base_incr;)
          (i32.trunc_f64_u 
            (f64.div 
              (f64.mul 
                (f64.convert_i32_u (i32.load (&psg.clk;)))
                (f64.const {$ 1 << $.GETA_BITS})
              )
              (f64.mul
                (f64.convert_i32_u (i32.load (&psg.rate;)))
                (f64.const 16)
              )
            )
          )
        )
      )

    )
  )

  (func $set_rate (param $r i32) 
    (i32.store (&psg.rate;) 
     (select (local.get $r) (i32.const 44100) (local.get $r))
    )
    (call $internal_refresh)
  )

  
  (func $set_quality (param $q i32)
    (i32.store 
      (&psg.quality;)
      (local.get $q)
    )
    (call $internal_refresh)
  )

  (func $init (param $c i32) (param $r i32)
    (call $set_volume_mode (i32.const {$.EMU2149_VOL_DEFAULT}))
    (i32.store (&psg.clk;) (local.get $c))
    (i32.store 
      (&psg.rate;)
      (select
        (i32.const 44100)
        (local.get $r)
        (i32.eqz (local.get $r))
      )
    )
    (call $set_quality (i32.const 0))
  )
  
  (func $set_volume_mode (param $type i32)
    (i32.store 
      (&psg.voltbl;) 
      (i32.add 
        (&psg.voltbl_;) 
        (i32.shl (local.get $type) (@psg.voltbl + 5;))
      )
    )
  )

  (func $set_mask (param $mask i32) (result i32)
    (i32.load (&psg.mask;))
    (i32.store (&psg.mask;) (local.get $mask))
  )

  (func $toggle_mask (param $mask i32) (result i32)
    (i32.load (&psg.mask;))
    (i32.store (&psg.mask;)
      (i32.xor (i32.load (&psg.mask;)) (i32.const 0xffff_ffff))
    )
  )

  (func $reset
    (local $c i32)
    (local $work i32)
    (local $size i32)
    (local $count i32)
    (local $freq i32)
    (local $edge i32)
    (local $volume i32)
    (local $ch_out i32)

    (local.set $count (&psg.count;))
    (local.set $freq (&psg.freq;))
    (local.set $edge (&psg.edge;))
    (local.set $volume (&psg.volume;))
    (local.set $ch_out (&psg.ch_out;))

    (i32.store (&psg.base_count;) (i32.const 0))
    (local.set $c (i32.const 3))

    (block $exit
      (loop $loop
        (br_if $exit (i32.eqz (local.get $c)))
        (local.set $c (i32.sub (local.get $c) (i32.const 1)))
        (i32.store (local.get $count) (i32.const 0x1000))
        (i32.store (local.get $freq) (i32.const 0))
        (i32.store (local.get $edge) (i32.const 0))
        (i32.store (local.get $volume) (i32.const 0))
        (i32.store (local.get $ch_out) (i32.const 0))
        (local.set $count (i32.add (local.get $count) (#psg.count;)))
        (local.set $freq (i32.add (local.get $freq) (#psg.freq;)))
        (local.set $edge (i32.add (local.get $edge) (#psg.edge;)))
        (local.set $volume (i32.add (local.get $volume) (#psg.volume;)))
        (local.set $ch_out (i32.add (local.get $ch_out) (#psg.ch_out;)))
        (br $loop)
      )
    )
    
    (i32.store (&psg.mask;) (i32.const 0))

    ;; レジスタの初期化
    (local.set $c (i32.const 16))
    (local.set $work (&psg.reg;))
    (block $exit_reg
      (loop $loop_reg
        (br_if $exit_reg (i32.eqz(local.get $c) ))
        (local.set $c (i32.sub (local.get $c) (i32.const 1)))
        (i32.store (local.get $work) (i32.const 0))
        (local.set $work (i32.add (local.get $work) (#psg.reg;)) )
        (br $loop_reg)
      )
    )

    (i32.store (&psg.adr;) (i32.const 0))
    (i32.store (&psg.noise_seed;) (i32.const 0xffff))
    (i32.store (&psg.noise_count;) (i32.const 0x40))
    (i32.store (&psg.noise_freq;) (i32.const 0))

    (i32.store (&psg.env_volume;) (i32.const 0))
    (i32.store (&psg.env_ptr;) (i32.const 0))
    (i32.store (&psg.env_freq;) (i32.const 0))
    (i32.store (&psg.env_count;) (i32.const 0))
    (i32.store (&psg.env_pause;) (i32.const 1))

    (i32.store (&psg.out;) (i32.const 0))

  )

  (func $read_io (result i32)
    (i32.load
      (i32.add 
        (&psg.reg;)
        (i32.shl (i32.load (&psg.adr;)) (i32.const {$ Math.log2($.psg.adr[$attributes].size) | 0 }))
      ) 
    )
  )
  (func $read_reg (param $reg i32) (result i32)
    (i32.load
      (i32.add 
        (&psg.reg;)
        (i32.shl (local.get $reg) (@psg.reg;))      
      )
    )
  )
  
  (func $write_io (param $adr i32) (param $val i32)
    (if 
      (i32.and (local.get $adr) (i32.const 1))
      (then
        (call $write_reg (i32.load (&psg.adr;)) (local.get $val))
      )
      (else
        (i32.store (&psg.adr;) (i32.and (local.get $val) (i32.const 0x1f))) 
      )
    )
  )

  (func $update_output 
    (local $incr i32)
    (local $noise i32)
    (local $i i32)
    (local $offset i32)

    (i32.store (&psg.base_count;) 
      (i32.add 
        (i32.load (&psg.base_count;))
        (i32.load (&psg.base_incr;))
      )
    )
    (local.set $incr (i32.shr_u (i32.load (&psg.base_count;)) (i32.const {$.GETA_BITS})))
    (i32.store 
      (&psg.base_count;)
      (i32.and 
        (i32.load(&psg.base_count;))
        (i32.const {$.SHIFT_BITS_MASK})
      )
    )

    ;; Envelope
    (i32.store 
      (&psg.env_count;)
      (i32.add 
        (i32.load (&psg.env_count;)) 
        (local.get $incr)
      )
    )
    
    (block $exit_envelope
      (loop $loop_envelope
        (br_if $exit_envelope
          (i32.or 
            (i32.lt_u (i32.load (&psg.env_count;)) (i32.const 0x10000))
            (i32.eqz (i32.load (&psg.env_freq;) ))
          )
        )
        (if (i32.eqz (i32.load (&psg.env_pause;)))
          (then
            (if (i32.load (&psg.env_face;))
              (then
                (i32.store 
                  (&psg.env_ptr;)
                  (i32.and 
                    (i32.add
                      (i32.load (&psg.env_ptr;))
                      (i32.const 1)
                    )
                    (i32.const 0x3f)
                  )
                )
              )
              (else
                (i32.store 
                  (&psg.env_ptr;)
                  (i32.and 
                    (i32.add
                      (i32.load (&psg.env_ptr;))
                      (i32.const 0x3f)
                    )
                    (i32.const 0x3f)
                  )
                )
              
              )
            )
          )
        )

        (if
          (i32.and (i32.load (&psg.env_ptr;)) (i32.const 0x20))
          (then
            (if 
              (i32.load (&psg.env_continue;))
              (then
                (if
                  (i32.xor 
                    (i32.load (&psg.env_alternate;))
                    (i32.load (&psg.env_hold;))
                  )
                  (then
                    (i32.store (&psg.env_face;)
                      (i32.xor
                        (i32.load (&psg.env_face;))
                        (i32.const 1)
                      )
                    )
                  )
                )
                (if
                  (i32.load (&psg.env_hold;))
                  (then
                    (i32.store (&psg.env_pause;) (i32.const 1))
                  )
                )
                (i32.store 
                  (&psg.env_ptr;)
                  (select
                    (i32.const 0)
                    (i32.const 0x1f)
                    (i32.load (&psg.env_face;))
                  )
                )
              )
              (else
                (i32.store (&psg.env_pause;) (i32.const 1))
                (i32.store (&psg.env_ptr;) (i32.const 0))
              )
            )
          )
        )
        (i32.store
          (&psg.env_count;)
          (i32.sub
            (i32.load (&psg.env_count;)) 
            (i32.load (&psg.env_freq;)) 
          ) 
        ) 
        (br $loop_envelope)
      )
    )

    ;; Noise
    (i32.store 
      (&psg.noise_count;)
      (i32.add
        (i32.load (&psg.noise_count;))
        (local.get $incr)
      )
    )
    (if
      (i32.and (i32.load (&psg.noise_count;)) (i32.const 0x40))
      (then
        (if
          (i32.and 
            (i32.load (&psg.noise_seed;))
            (i32.const 1)
          )
          (then
            (i32.store
              (&psg.noise_seed;)
              (i32.xor 
                (i32.load (&psg.noise_seed;))
                (i32.const 0x24000)
              )
            )
          )
        )
        (i32.store 
            (&psg.noise_seed;)
            (i32.shr_u 
              (i32.load (&psg.noise_seed;))
              (i32.const 1)
            )
        )
        (i32.store
          (&psg.noise_count;)
          (i32.sub 
            (i32.load (&psg.noise_count;))
            (select 
              (i32.load (&psg.noise_freq;))
              (i32.const 2)
              (i32.load (&psg.noise_freq;))
            )
          )
        )
      )
    )
    
    (local.set $noise
      (i32.and 
        (i32.load (&psg.noise_seed;))
        (i32.const 1)
      )
    )

    ;; Tone
    (local.set $i (i32.const 3))
    (block $tone_exit
      (loop $tone_loop
        (br_if $tone_exit (i32.eqz (local.get $i)))
        (local.set $i
          (i32.sub (local.get $i) (i32.const 1))
        )

        (local.set $offset
            (i32.shl
              (local.get $i)
              (i32.const 2)
            )
        )
       (i32.store 
          (i32.add 
            (&psg.count;)
            (local.get $offset)
          )
          (i32.add
            (i32.load
              (i32.add 
                (&psg.count;)
                (local.get $offset)
              ) 
            )
            (local.get $incr)
          )
        )
        (if
          (i32.and 
            (i32.load
              (i32.add 
                (&psg.count;)
                (local.get $offset)
              )
            )
            (i32.const 0x1000)
          )
          (then
            (if
              (i32.gt_u
                (i32.load
                  (i32.add 
                    (&psg.freq;)
                    (local.get $offset)
                  )
                )
                (i32.const 1)
              )
              (then
                (i32.store
                  (i32.add 
                    (&psg.edge;)
                    (local.get $offset)
                  )
                  (i32.xor
                    (i32.load
                      (i32.add 
                        (&psg.edge;)
                        (local.get $offset)
                      )
                    )
                    (i32.const 0x1 )
                  )
                )
                (i32.store
                  (i32.add 
                    (&psg.count;)
                    (local.get $offset)
                  )
                  (i32.sub
                    (i32.load
                      (i32.add 
                        (&psg.count;)
                        (local.get $offset)
                      )
                    )
                    (i32.load
                      (i32.add 
                        (&psg.freq;)
                        (local.get $offset)
                      )
                    )
                  )
                )
              )
              (else
                (i32.store
                  (i32.add 
                    (&psg.edge;)
                    (local.get $offset)
                  )
                  (i32.const 1)

                )
              )
            )
          )
        )


        
       
        (if
          (i32.and
            (select (i32.const 1) (i32.const 0) 
              (i32.or
                (i32.load (i32.add (&psg.tmask;) (local.get $offset)))
                (i32.load (i32.add (&psg.edge;) (local.get $offset)))
              )
            )
            (select (i32.const 1) (i32.const 0)
              (i32.or
                (i32.load (i32.add (&psg.nmask;) (local.get $offset)))
                (local.get $noise)
              )
            )
          )
          (then
            (if
              (i32.eqz 
                (i32.and
                  (i32.load
                    (i32.add 
                      (&psg.volume;)
                      (local.get $offset)
                    )
                  )
                  (i32.const 32)
                )
              )
              (then
                (i32.store
                  (i32.add
                    (&psg.ch_out;)
                    (local.get $offset)
                  )
                  (i32.add
                    (i32.load 
                      (i32.add
                        (&psg.ch_out;)
                        (local.get $offset)
                      )
                    )
                    (i32.shl
                      (i32.load
                        (i32.add
                          (i32.load (&psg.voltbl;))
                          (i32.shl
                            (i32.and 
                              (i32.load
                                (i32.add
                                  (&psg.volume;)
                                  (local.get $offset)
                                )
                              )
                              (i32.const 31)
                            )
                            (@psg.voltbl;)
                          )
                        )
                      )
                      (i32.const 4)
                    )
                  )
                )  
              )
              (else
                (i32.store
                  (i32.add
                    (&psg.ch_out;)
                    (local.get $offset)
                  )
                  (i32.add
                    (i32.load
                      (i32.add
                        (&psg.ch_out;)
                        (local.get $offset)
                      )
                    )
                    (i32.shl
                      (i32.load
                        (i32.add 
                          (i32.load (&psg.voltbl;))
                          (i32.shl 
                            (i32.load (&psg.env_ptr;))
                            (@psg.voltbl_;)
                          )
                        )
                      )
                      (i32.const 4)
                    )
                  )
                )
              )
            )
          )

        )

        (i32.store 
          (i32.add
            (&psg.ch_out;)
            (local.get $offset)
          )
          (i32.shr_u
            (i32.load
              (i32.add
                (&psg.ch_out;)
                (local.get $offset)
              )
            )
            (i32.const 1)
          )
        )
        (br $tone_loop)
      )
    )
  )

  (func $mix_output (result i32)
    (i32.store
      (&psg.out;)
      (i32.add
        (i32.load (&psg.ch_out;))
        (i32.add
          (i32.load (&psg.ch_out[1];))
          (i32.load (&psg.ch_out[2];))
        )
      )
    )
    (i32.load (&psg.out;))
  )

  (func $calc (result i32)
    (if (i32.eqz (i32.load (&psg.quality;)))
      (then
        call $update_output
        call $mix_output
        return
      )
    )
    (block $rate_loop_exit
      (loop $rate_loop
        (br_if $rate_loop_exit 
          (i32.le_u (i32.load(&psg.realstep;)) (i32.load(&psg.psgtime;)))
        )
        (i32.store
          (&psg.psgtime;)
          (i32.add
            (i32.load(&psg.psgtime;))
            (i32.load(&psg.psgstep;))
          )
        )
        call $update_output
        (br $rate_loop)
      )
    )
    (i32.store
      (&psg.psgtime;)
      (i32.sub
        (i32.load(&psg.psgtime;))
        (i32.load(&psg.realstep;))
      )
    )

    call $mix_output
  )

  (func $calc2 (param $numOfSamples i32)(result i32)
    (if (i32.eqz (i32.load (&psg.quality;)))
      (then
        (block $loop-normal-exit
          (loop $loop-normal
          )
            
        call $update_output
        call $mix_output
        return
      )
    )
    (block $rate_loop_exit
      (loop $rate_loop
        (br_if $rate_loop_exit 
          (i32.le_u (i32.load(&psg.realstep;)) (i32.load(&psg.psgtime;)))
        )
        (i32.store
          (&psg.psgtime;)
          (i32.add
            (i32.load(&psg.psgtime;))
            (i32.load(&psg.psgstep;))
          )
        )
        call $update_output
        (br $rate_loop)
      )
    )
    (i32.store
      (&psg.psgtime;)
      (i32.sub
        (i32.load(&psg.psgtime;))
        (i32.load(&psg.realstep;))
      )
    )

    call $mix_output
  )

  (func $write_reg (param $reg i32) (param $val i32) (local $c i32) (local $w i32)
    (if (i32.gt_u (local.get $reg) (i32.const 15))
      (then
        return
      )
    )
    (local.set $val
      (i32.and
        (local.get $val)
        (i32.load 
          (i32.add 
            (&psg.regmsk;)
            (i32.shl 
              (local.get $reg)
              (@psg.regmsk;)
            )
          )
        )
      ) 
    )

    (i32.store
      (i32.add 
        (&psg.reg;)
        (i32.shl 
          (local.get $reg)
          (@psg.reg;)
        )
      )
      (local.get $val)
    )
    
    (block $default
      (br_if $default (i32.gt_u (local.get $reg) (i32.const 13))) 
      (block $reg0_5
        (block $reg6
          (block $reg7
            (block $reg8_10
              (block $reg11_12
                (block $reg13
                  (br_table 
                    $reg0_5 $reg0_5 $reg0_5 $reg0_5 $reg0_5 $reg0_5 $reg6 $reg7 
                    $reg8_10 $reg8_10 $reg8_10 $reg11_12 $reg11_12 $reg13
                    (local.get $reg)
                  )
                )
                ;; reg 13
                (i32.store
                  (&psg.env_continue;) 
                  (i32.and
                    (i32.shr_u (local.get $val) (i32.const 3))
                    (i32.const 1)
                  )
                )
                (i32.store
                  (&psg.env_attack;) 
                  (i32.and
                    (i32.shr_u (local.get $val) (i32.const 2))
                    (i32.const 1)
                  )
                )
                (i32.store
                  (&psg.env_alternate;) 
                  (i32.and
                    (i32.shr_u (local.get $val) (i32.const 1))
                    (i32.const 1)
                  )
                )
                (i32.store
                  (&psg.env_hold;) 
                  (i32.and
                    (local.get $val)
                    (i32.const 1)
                  )
                )
                (i32.store
                  (&psg.env_face;) 
                  (i32.load (&psg.env_attack;)) 
                )
                (i32.store
                  (&psg.env_pause;) 
                  (i32.const 0) 
                )
                (i32.store
                  (&psg.env_count;) 
                  (i32.sub 
                    (i32.const 0x10000)
                    (i32.load (&psg.env_freq;))
                  )
                )
                (i32.store
                  (&psg.env_ptr;)
                  (select
                    (i32.const 0)
                    (i32.const 0x1f)
                    (i32.load (&psg.env_face;))
                  )
                )
                return
              )
              ;; reg11-12
              (i32.store
                (&psg.env_freq;)
                (i32.add 
                  (i32.shl
                    (i32.load (&psg.reg[12];))
                    (i32.const 8)
                  )
                  (i32.load(&psg.reg[11];))
                )
              )
              return
            )
            ;; reg 8-10
            (i32.store
              (i32.add 
                (&psg.volume;)
                (i32.shl 
                  (i32.sub (local.get $reg) (i32.const 8)) 
                  (@psg.volume;)
                )
              )
              (i32.shl
                (local.get $val)
                (i32.const 1)
              )
            )
            return
          )
          ;; reg 7
          ;;(local.set $val (i32.xor (i32.const 0xff) (local.get $val)))
          (i32.store (&psg.tmask[0];) (i32.and (local.get $val) (i32.const 1)))
          (i32.store (&psg.tmask[1];) (i32.and (local.get $val) (i32.const 2)))
          (i32.store (&psg.tmask[2];) (i32.and (local.get $val) (i32.const 4)))

          (i32.store (&psg.nmask[0];) (i32.and (local.get $val) (i32.const 8)))
          (i32.store (&psg.nmask[1];) (i32.and (local.get $val) (i32.const 16)))
          (i32.store (&psg.nmask[2];) (i32.and (local.get $val) (i32.const 32)))

          return
        )
        ;; reg 6
        (i32.store 
          (&psg.noise_freq;)
          (i32.shl
            (i32.and
              (local.get $val)
              (i32.const 31)
            )
            (i32.const 1)
          )
        )
        return
      ) 
      ;; reg 0-5
      (local.set $c 
        (i32.shr_u
          (local.get $reg)
          (i32.const 1)
        )
      )

      (i32.store
        (i32.add
          (&psg.freq;)
          (i32.shl (local.get $c) (@psg.freq;))
        )
        (i32.add
          (i32.shl 
            (i32.and 
              (i32.load
                (i32.add 
                  (&psg.reg;)
                  (i32.shl
                    (i32.add
                      (i32.shl
                        (local.get $c)
                        (i32.const 1)
                      )
                      (i32.const 1)
                    )
                    (@psg.reg;)
                  )
                )
              )
              (i32.const 15)
            )
            (i32.const 8)
          )
          (i32.load
            (i32.add
              (&psg.reg;)
              (i32.shl
                (i32.shl 
                  (local.get $c)
                  (i32.const 1)
                )
                (@psg.reg;)
              )
            )
          )
        )
      )
      return
    )
  )
)

動機

wasmのテキスト・モード(wat)でコードを書こうしたときに、定数ラベルや定数式を処理できれば楽にコーディングできるのではないかと考えたことがきっかけです。

実装について

構文パーサはpeg.jsを使用しています。 プリプロセスを実行する部分はnode.jsを使用しており、プリプロセス後のソースコードをwabtに引き渡し、wasmバイナリ化しています。

インストール方法

  1. git cloneします。
  2. クローンしたディレクトリにて npm installを実行します。
  3. cliを使用する場合はさらにnpm install -gします。

状態

作成中の状態です。wsl上でのみ実行できることを確認しています。node.js環境でのみ動作します。 自分用に作成しているので、エラー処理などかなりいい加減なものになっていますのでご注意ください。

サンプルの実行

npm run testでテストが走ります。

コマンドライン

bin/mwasm コマンドで実行します。

mwasm ソーステキスト名 [-o wasmバイナリ出力ファイル名]

-oを指定しない場合はコンソールにプリプロセス後のソースコードを表示します。

プリプロセッサの構文について

{ JSステートメントブロック }

JSステートメントをプリプロセス時に実行します。結果をreturnで返すとその位置に値が埋め込まれます。 コンテキストオブジェクトとして$が用意されており、コードブロック内で書き込み・参照が可能です。 ローカル変数なども定義できますが、コードブロック中でのみ有効です。

{
  // JSによるWASMソースコード生成
  let instructions = '';
  for(let i = 0;i < 4; ++ i ){
    ++$.X; 
    instructions += `
  i32.const ${$.X + $.Y}
  i32.add`;
  }
  return instructions;
}

{@ JSステートメントブロック }

JSステートメントをプロプロセス時に実行しますが値を埋め込みません。

{@
// コンテキスト$ にプロパティを設定する
$.X = 0x1;
$.Y = 2;
$.Z = 0x3;
}

{$ JS式}

JS式を実行し、結果をその位置に埋め込みます。

i32.const {$ $.X + $.Y }

{@struct}

構造体を定義します。

{@map}

リニアメモリ中のメモリ配置を定義します。定義にには{@struct}で定義した構造体も型として使用できます。

{@include JS式}

JS式の結果得られるpathにあるファイルをインクルードします。

{@include './test_inc.mwat'}

{@if JS式} ソース1 [{@else} ソース2] {@endif}

JS式が真の場合ソース1を埋め込み、そうでない場合はソース2を埋め込みます。 @else ソース2は省略可能です。

{@if $.X < 1}

...ソース1

{@else}

...ソース2

{@endif}

開発について

  • パッケージのバンドルにはrollupを使用しています。
  • 構文パーサはpeg.jsを使用しております。
You can’t perform that action at this time.