aboutsummaryrefslogtreecommitdiff
path: root/contrib/bearssl/T0/kern.t0
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bearssl/T0/kern.t0')
-rw-r--r--contrib/bearssl/T0/kern.t0309
1 files changed, 309 insertions, 0 deletions
diff --git a/contrib/bearssl/T0/kern.t0 b/contrib/bearssl/T0/kern.t0
new file mode 100644
index 000000000000..9fce4f84d301
--- /dev/null
+++ b/contrib/bearssl/T0/kern.t0
@@ -0,0 +1,309 @@
+: \ `\n parse drop ; immediate
+
+\ This file defines the core non-native functions (mainly used for
+\ parsing words, i.e. not part of the generated output). The line above
+\ defines the syntax for comments.
+
+\ Define parenthesis comments.
+\ : ( `) parse drop ; immediate
+
+: else postpone ahead 1 cs-roll postpone then ; immediate
+: while postpone if 1 cs-roll ; immediate
+: repeat postpone again postpone then ; immediate
+
+: ['] ' ; immediate
+: [compile] compile ; immediate
+
+: 2drop drop drop ;
+: dup2 over over ;
+
+\ Local variables are defined with the native word '(local)'. We define
+\ a helper construction that mimics what is found in Apple's Open Firmware
+\ implementation. The syntax is: { a b ... ; c d ... }
+\ I.e. there is an opening brace, then some names. Names appearing before
+\ the semicolon are locals that are both defined and then filled with the
+\ values on stack (in stack order: { a b } fills 'b' with the top-of-stack,
+\ and 'a' with the value immediately below). Names appearing after the
+\ semicolon are not initialized.
+: __deflocal ( from_stack name -- )
+ dup (local) swap if
+ compile-local-write
+ else
+ drop
+ then ;
+: __deflocals ( from_stack -- )
+ next-word
+ dup "}" eqstr if
+ 2drop ret
+ then
+ dup ";" eqstr if
+ 2drop 0 __deflocals ret
+ then
+ over __deflocals
+ __deflocal ;
+: {
+ -1 __deflocals ; immediate
+
+\ Data building words.
+: data:
+ new-data-block next-word define-data-word ;
+: hexb|
+ 0 0 { acc z }
+ begin
+ char
+ dup `| = if
+ z if "Truncated hexadecimal byte" puts cr exitvm then
+ ret
+ then
+ dup 0x20 > if
+ hexval
+ z if acc 4 << + data-add8 else >acc then
+ z not >z
+ then
+ again ;
+
+\ Convert hexadecimal character to number. Complain loudly if conversion
+\ is not possible.
+: hexval ( char -- x )
+ hexval-nf dup 0 < if "Not an hex digit: " puts . cr exitvm then ;
+
+\ Convert hexadecimal character to number. If not an hexadecimal digit,
+\ return -1.
+: hexval-nf ( char -- x )
+ dup dup `0 >= swap `9 <= and if `0 - ret then
+ dup dup `A >= swap `F <= and if `A - 10 + ret then
+ dup dup `a >= swap `f <= and if `a - 10 + ret then
+ drop -1 ;
+
+\ Convert decimal character to number. Complain loudly if conversion
+\ is not possible.
+: decval ( char -- x )
+ decval-nf dup 0 < if "Not a decimal digit: " puts . cr exitvm then ;
+
+\ Convert decimal character to number. If not a decimal digit,
+\ return -1.
+: decval-nf ( char -- x )
+ dup dup `0 >= swap `9 <= and if `0 - ret then
+ drop -1 ;
+
+\ Commonly used shorthands.
+: 1+ 1 + ;
+: 2+ 2 + ;
+: 1- 1 - ;
+: 2- 2 - ;
+: 0= 0 = ;
+: 0<> 0 <> ;
+: 0< 0 < ;
+: 0> 0 > ;
+
+\ Get a 16-bit value from the constant data block. This uses big-endian
+\ encoding.
+: data-get16 ( addr -- x )
+ dup data-get8 8 << swap 1+ data-get8 + ;
+
+\ The case..endcase construction is the equivalent of 'switch' is C.
+\ Usage:
+\ case
+\ E1 of C1 endof
+\ E2 of C2 endof
+\ ...
+\ CN
+\ endcase
+\
+\ Upon entry, it considers the TOS (let's call it X). It will then evaluate
+\ E1, which should yield a single value Y1; at that point, the X value is
+\ still on the stack, just below Y1, and must remain untouched. The 'of'
+\ word compares X with Y1; if they are equal, C1 is executed, and then
+\ control jumps to after the 'endcase'. The X value is popped from the
+\ stack immediately before evaluating C1.
+\
+\ If X and Y1 are not equal, flow proceeds to E2, to obtain a value Y2 to
+\ compare with X. And so on.
+\
+\ If none of the 'of' clauses found a match, then CN is evaluated. When CN
+\ is evaluated, the X value is on the TOS, and CN must either leave it on
+\ the stack, or replace it with exactly one value; the 'endcase' word
+\ expects (and drops) one value.
+\
+\ Implementation: this is mostly copied from ANS Forth specification,
+\ although simplified a bit because we know that our control-flow stack
+\ is independent of the data stack. During compilation, the number of
+\ clauses is maintained on the stack; each of..endof clause really is
+\ an 'if..else' that must be terminated with a matching 'then' in 'endcase'.
+
+: case 0 ; immediate
+: of 1+ postpone over postpone = postpone if postpone drop ; immediate
+: endof postpone else ; immediate
+: endcase
+ postpone drop
+ begin dup while 1- postpone then repeat drop ; immediate
+
+\ A simpler and more generic "case": there is no management for a value
+\ on the stack, and each test is supposed to come up with its own boolean
+\ value.
+: choice 0 ; immediate
+: uf 1+ postpone if ; immediate
+: ufnot 1+ postpone ifnot ; immediate
+: enduf postpone else ; immediate
+: endchoice begin dup while 1- postpone then repeat drop ; immediate
+
+\ C implementations for native words that can be used in generated code.
+add-cc: co { T0_CO(); }
+add-cc: execute { T0_ENTER(ip, rp, T0_POP()); }
+add-cc: drop { (void)T0_POP(); }
+add-cc: dup { T0_PUSH(T0_PEEK(0)); }
+add-cc: swap { T0_SWAP(); }
+add-cc: over { T0_PUSH(T0_PEEK(1)); }
+add-cc: rot { T0_ROT(); }
+add-cc: -rot { T0_NROT(); }
+add-cc: roll { T0_ROLL(T0_POP()); }
+add-cc: pick { T0_PICK(T0_POP()); }
+add-cc: + {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+}
+add-cc: - {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+}
+add-cc: neg {
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+}
+add-cc: * {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+}
+add-cc: / {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a / b);
+}
+add-cc: u/ {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a / b);
+}
+add-cc: % {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a % b);
+}
+add-cc: u% {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a % b);
+}
+add-cc: < {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+}
+add-cc: <= {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+}
+add-cc: > {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+}
+add-cc: >= {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+}
+add-cc: = {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+}
+add-cc: <> {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+}
+add-cc: u< {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a < b));
+}
+add-cc: u<= {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a <= b));
+}
+add-cc: u> {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a > b));
+}
+add-cc: u>= {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a >= b));
+}
+add-cc: and {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+}
+add-cc: or {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+}
+add-cc: xor {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a ^ b);
+}
+add-cc: not {
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+}
+add-cc: << {
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+}
+add-cc: >> {
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+}
+add-cc: u>> {
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+}
+add-cc: data-get8 {
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+}
+
+add-cc: . {
+ extern int printf(const char *fmt, ...);
+ printf(" %ld", (long)T0_POPi());
+}
+add-cc: putc {
+ extern int printf(const char *fmt, ...);
+ printf("%c", (char)T0_POPi());
+}
+add-cc: puts {
+ extern int printf(const char *fmt, ...);
+ printf("%s", &t0_datablock[T0_POPi()]);
+}
+add-cc: cr {
+ extern int printf(const char *fmt, ...);
+ printf("\n");
+}
+add-cc: eqstr {
+ const void *b = &t0_datablock[T0_POPi()];
+ const void *a = &t0_datablock[T0_POPi()];
+ T0_PUSH(-(int32_t)(strcmp(a, b) == 0));
+}