Console

em.lang/Console.em
import em from '@$$emscript'
export const $U = em.$declare('MODULE')

import * as Common from '@em.mcu/Common.em'

export function putbuf(buf: frame_t<u8>) {
    for (let p of buf) putch(p.$$)
}

export function putch(ch: u8) {
    Common.ConsoleUart.$$.put(ch)
}

export function puts(sp: ptr_t<u8>) {
    while (sp.$$) {
        putch(sp.$$)
        sp.$inc()
    }
}

export function wrC(data: u8) {
    putch(data)
}

export function wrU8(data: u8) {
    putch(0x81)
    putch(data)
}

export function wrU16(data: u16) {
    putch(0x82)
    let b = <u8>((data >> 8) & 0xFF)
    putch(b)
    b = <u8>((data >> 0) & 0xFF)
    putch(b)
}

export function wrU32(data: u32) {
    putch(0x84)
    let b = <u8>((data >> 24) & 0xFF)
    putch(b)
    b = <u8>((data >> 16) & 0xFF)
    putch(b)
    b = <u8>((data >> 8) & 0xFF)
    putch(b)
    b = <u8>((data >> 0) & 0xFF)
    putch(b)
}

// private

e$`static inline void wr(em::u8 data) { wrU8(data); }`
e$`static inline void wr(em::i8 data) { wrU8((em::u8)data); }`
e$`static inline void wr(em::u16 data) { wrU16(data); }`
e$`static inline void wr(em::i16 data) { wrU16((em::u16)data); }`
e$`static inline void wr(em::u32 data) { wrU32(data); }`
e$`static inline void wr(em::i32 data) { wrU32((em::u32)data); }`

const Args = $array($u32(), 6)
const NumBuf = $array($u8(), 10)

function c2d(ch: u8): u8 { return ch - c$`0` }

function formatNum(buf: frame_t<u8>, num: u32, base: u8, width: i8, pad: u8): frame_t<u8> {
    let HEXDIGS = t$`0123456789ABCDEF`
    let idx = buf.$len
    for (; ;) {
        width -= 1
        idx -= 1
        buf[idx] = HEXDIGS[(num % base)]
        num /= base
        if (num == 0) break
    }
    while (width > 0) {
        width -= 1
        idx -= 1
        buf[idx] = pad
    }
    return buf.$frame(idx, 0)
}

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

export function print(fmt: text_t, a1: arg_t = 0, a2: arg_t = 0, a3: arg_t = 0, a4: arg_t = 0, a5: arg_t = 0, a6: arg_t = 0) {
    let args = Args.$make()
    let num_buf = NumBuf.$make()
    args[0] = <u32>a1
    args[1] = <u32>a2
    args[2] = <u32>a3
    args[3] = <u32>a4
    args[4] = <u32>a5
    args[5] = <u32>a6
    let argp = args.$ptr()
    let idx = 0
    while (idx < fmt.$len) {
        let width = 0
        let pad = c$` `
        let ch = fmt[idx++]
        if (ch != c$`%`) {
            putch(ch)
            continue
        }
        ch = fmt[idx++]
        if (ch == c$`0`) {
            pad = ch
            ch = fmt[idx++]
        }
        while (isDigit(ch)) {
            width = width * 10 + c2d(ch)
            ch = fmt[idx++]
        }
        if (ch == c$`d`) {
            let dn = <i32>argp.$$
            argp.$inc()
            if (dn < 0) {
                putch(c$`-`)
                dn = -dn
            }
            let nb = formatNum(num_buf, <u32>dn, 10, width, pad)
            putbuf(nb)
        }
        else if (ch == c$`x`) {
            let xn = <u32>argp.$$
            argp.$inc()
            let nb = formatNum(num_buf, xn, 16, width, pad)
            putbuf(nb)
        }
        else if (ch == c$`c`) {
            let cn = argp.$$
            argp.$inc()
            putch(cn)
        }
        else if (ch == c$`s`) {
            let sp = <ptr_t<u8>><unknown>argp.$$
            argp.$inc()
            puts(sp)
        }
        else {
            putch(ch)
        }
    }
}