StateBench

em.bench.coremark/StateBench.em
import em from '@$$emscript'
export const $U = em.$declare('MODULE')

import * as Crc from '@em.bench.coremark/Crc.em'
import * as Utils from '@em.bench.coremark/Utils.em'

export const memsize = $config<u16>(0)

const NUM_STATES = 8

enum State {
    START, INVALID, S1, S2, INT, FLOAT, EXPONENT, SCIENTIFIC
}

const intPat = $table<text_t>('ro')
const fltPat = $table<text_t>('ro')
const sciPat = $table<text_t>('ro')
const errPat = $table<text_t>('ro')

const intPatLen = $config<u16>(0)
const fltPatLen = $config<u16>(0)
const sciPatLen = $config<u16>(0)
const errPatLen = $config<u16>(0)

const StateCnt = $array($u32(), NUM_STATES)

var membuf = $table<u8>('rw')

export namespace em$meta {

    export function em$init() {
        intPat.$add(t$`5012`)
        intPat.$add(t$`1234`)
        intPat.$add(t$`-874`)
        intPat.$add(t$`+122`)
        intPatLen.$$ = intPat[0].$len
        //
        fltPat.$add(t$`35.54400`)
        fltPat.$add(t$`.1234500`)
        fltPat.$add(t$`-110.700`)
        fltPat.$add(t$`+0.64400`)
        fltPatLen.$$ = fltPat[0].$len
        //
        sciPat.$add(t$`5.500e+3`)
        sciPat.$add(t$`-.123e-2`)
        sciPat.$add(t$`-87e+832`)
        sciPat.$add(t$`+0.6e-12`)
        sciPatLen.$$ = sciPat[0].$len
        //
        errPat.$add(t$`T0.3e-1F`)
        errPat.$add(t$`-T.T++Tq`)
        errPat.$add(t$`1T3.4e4z`)
        errPat.$add(t$`34.0e-T^`)
        errPatLen.$$ = errPat[0].$len
    }

    export function em$construct() {
        for (let i = 0; i < memsize.$$; i++) membuf.$add(0)
    }
}

function isDigit(ch: u8): bool_t {
    return ch >= c$`0` && ch <= c$`9`
}

export function kind(): Utils.Kind {
    return Utils.Kind.STATE
}

function nextState(pStr: ref_t<ptr_t<u8>>, transCnt: index_t<u32>): State {
    let str = pStr.$$
    let state = <State>State.START
    for (; str.$$ && state != State.INVALID; str.$inc()) {
        let ch = str.$$
        if (ch == c$`,`) {
            str.$inc()
            break
        }
        switch (state) {
            case State.START:
                if (isDigit(ch)) {
                    state = State.INT
                }
                else if (ch == c$`+` || ch == c$`-`) {
                    state = State.S1
                }
                else if (ch == c$`.`) {
                    state = State.FLOAT
                }
                else {
                    state = State.INVALID
                    transCnt[ord(State.INVALID)] += 1
                }
                transCnt[ord(State.START)] += 1
                break
            case State.S1:
                if (isDigit(ch)) {
                    state = State.INT
                    transCnt[ord(State.S1)] += 1
                }
                else if (ch == c$`.`) {
                    state = State.FLOAT
                    transCnt[ord(State.S1)] += 1
                }
                else {
                    state = State.INVALID
                    transCnt[ord(State.S1)] += 1
                }
                break
            case State.INT:
                if (ch == c$`.`) {
                    state = State.FLOAT
                    transCnt[ord(State.INT)] += 1
                }
                else if (!isDigit(ch)) {
                    state = State.INVALID
                    transCnt[ord(State.INT)] += 1
                }
                break
            case State.FLOAT:
                if (ch == c$`E` || ch == c$`e`) {
                    state = State.S2
                    transCnt[ord(State.FLOAT)] += 1
                }
                else if (!isDigit(ch)) {
                    state = State.INVALID
                    transCnt[ord(State.FLOAT)] += 1
                }
                break
            case State.S2:
                if (ch == c$`+` || ch == c$`-`) {
                    state = State.EXPONENT
                    transCnt[ord(State.S2)] += 1
                }
                else {
                    state = State.INVALID
                    transCnt[ord(State.S2)] += 1
                }
                break
            case State.EXPONENT:
                if (isDigit(ch)) {
                    state = State.SCIENTIFIC
                    transCnt[ord(State.EXPONENT)] += 1
                }
                else {
                    state = State.INVALID
                    transCnt[ord(State.EXPONENT)] += 1
                }
                break
            case State.SCIENTIFIC:
                if (!isDigit(ch)) {
                    state = State.INVALID
                    transCnt[ord(State.INVALID)] += 1
                }
                break
        }
    }
    pStr.$$ = str
    return state
}


function ord(state: State): u8 {
    return <u8>state
}

export function print() {
    let p = membuf.$ptr()
    let cnt = 0
    printf`\n%c`(c$`"`)
    while (p.$$) {
        if ((cnt++ % 8) == 0) {
            printf`\n    `()
        }
        for (; ;) {
            let c = p.$$
            p.$inc()
            if (c == c$`,`) break
            printf`%c`(c)
        }
        printf`, `()
    }
    printf`\n%c, count = %d\n`(c$`"`, cnt)
}

export function run(arg: i16): Utils.sum_t {
    if (arg < 0x22) arg = 0x22
    let finalCnt = StateCnt.$make()
    let transCnt = StateCnt.$make()
    for (let i = 0; i < NUM_STATES; i++) finalCnt[i] = transCnt[i] = 0
    scan(finalCnt, transCnt)
    scramble(Utils.getSeed(1), arg)
    scan(finalCnt, transCnt)
    scramble(Utils.getSeed(2), arg)
    let crc = Utils.getCrc(Utils.Kind.FINAL)
    for (let i = 0; i < NUM_STATES; i++) {
        crc = Crc.addU32(finalCnt[i], crc)
        crc = Crc.addU32(transCnt[i], crc)
    }
    return crc
}

function scan(finalCnt: index_t<u32>, transCnt: index_t<u32>) {
    let str = membuf.$ptr()
    let cnt = <u32>0
    while (str.$$) {
        let state = nextState($ref(str), transCnt)
        cnt += 1
        finalCnt[ord(state)] += 1
    }
}

function scramble(seed: Utils.seed_t, step: u32) {
    for (let idx = 0; idx < memsize.$$; idx += step) {
        if (membuf[idx] != c$`,`) membuf[idx] ^= <u8>seed
    }
}

export function setup() {
    let seed = Utils.getSeed(1)
    let p = membuf.$ptr()
    let total = 0
    let pat = t$``
    let plen = 0
    while ((total + plen + 1) < (memsize.$$ - 1)) {
        if (plen) {
            for (let i = 0; i < plen; i++) {
                p.$$ = pat[i]
                p.$inc()
            }
            p.$$ = c$`,`
            p.$inc()
            total += plen + 1
        }
        switch (++seed & 0x7) {
            case 0:
            case 1:
            case 2:
                pat = intPat[(seed >> 3) & 0x3]
                plen = intPatLen.$$
                break
            case 3:
            case 4:
                pat = fltPat[(seed >> 3) & 0x3]
                plen = fltPatLen.$$
                break
            case 5:
            case 6:
                pat = sciPat[(seed >> 3) & 0x3]
                plen = sciPatLen.$$
                break
            case 7:
                pat = errPat[(seed >> 3) & 0x3]
                plen = errPatLen.$$
                break
        }
    }
}