| 1 | # -*- tcl -*- |
|---|
| 2 | # ### ### ### ######### ######### ######### |
|---|
| 3 | ## Package description |
|---|
| 4 | |
|---|
| 5 | ## (struct::)Graph based ME Assembler, for use in grammar |
|---|
| 6 | ## translations. |
|---|
| 7 | |
|---|
| 8 | # ### ### ### ######### ######### ######### |
|---|
| 9 | ## Requisites |
|---|
| 10 | |
|---|
| 11 | namespace eval grammar::me::cpu::gasm {} |
|---|
| 12 | |
|---|
| 13 | # ### ### ### ######### ######### ######### |
|---|
| 14 | ## Implementation |
|---|
| 15 | |
|---|
| 16 | proc ::grammar::me::cpu::gasm::begin {g n {mode okfail} {note {}}} { |
|---|
| 17 | variable gas |
|---|
| 18 | array unset gas * |
|---|
| 19 | |
|---|
| 20 | # (Re)initialize the assmebler state, create the framework nodes |
|---|
| 21 | # upon which we will hang all instructions on. |
|---|
| 22 | |
|---|
| 23 | set gas(mode) $mode |
|---|
| 24 | set gas(node) $n |
|---|
| 25 | set gas(grap) $g |
|---|
| 26 | array set gas {last {} cond always} |
|---|
| 27 | |
|---|
| 28 | Nop $note ; /Label entry ; /Clear |
|---|
| 29 | if {$mode eq "okfail"} { |
|---|
| 30 | Nop Exit'OK ; /Label exit/ok ; /Clear |
|---|
| 31 | Nop Exit'FAIL ; /Label exit/fail ; /Clear |
|---|
| 32 | } elseif {$mode eq "halt"} { |
|---|
| 33 | Cmd icf_halt ; /Label exit/return ; /Clear |
|---|
| 34 | } else { |
|---|
| 35 | Cmd icf_ntreturn ; /Label exit/return ; /Clear |
|---|
| 36 | } |
|---|
| 37 | |
|---|
| 38 | /At entry |
|---|
| 39 | return |
|---|
| 40 | } |
|---|
| 41 | |
|---|
| 42 | proc ::grammar::me::cpu::gasm::done {__ t} { |
|---|
| 43 | variable gas |
|---|
| 44 | |
|---|
| 45 | # Save the framework nodes in a grammar tree and shut the |
|---|
| 46 | # assembler down. |
|---|
| 47 | |
|---|
| 48 | $t set $gas(node) gas::entry $gas(_entry) |
|---|
| 49 | |
|---|
| 50 | if {$gas(mode) eq "okfail"} { |
|---|
| 51 | $t set $gas(node) gas::exit::ok $gas(_exit/ok) |
|---|
| 52 | $t set $gas(node) gas::exit::fail $gas(_exit/fail) |
|---|
| 53 | } else { |
|---|
| 54 | $t set $gas(node) gas::exit $gas(_exit/return) |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | # Remember the node in the grammar tree which is responsible for |
|---|
| 58 | # this entry point. |
|---|
| 59 | |
|---|
| 60 | $gas(grap) node set $gas(_entry) expr $gas(node) |
|---|
| 61 | |
|---|
| 62 | array unset gas * |
|---|
| 63 | return |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | proc ::grammar::me::cpu::gasm::lift {t dst __ src} { |
|---|
| 67 | |
|---|
| 68 | $t set $dst gas::entry [$t get $src gas::entry] |
|---|
| 69 | $t set $dst gas::exit::ok [$t get $src gas::exit::ok] |
|---|
| 70 | $t set $dst gas::exit::fail [$t get $src gas::exit::fail] |
|---|
| 71 | return |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | proc ::grammar::me::cpu::gasm::state {} { |
|---|
| 75 | variable gas |
|---|
| 76 | return [array get gas] |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | proc ::grammar::me::cpu::gasm::state! {s} { |
|---|
| 80 | variable gas |
|---|
| 81 | array set gas $s |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | proc ::grammar::me::cpu::gasm::Inline {t node label} { |
|---|
| 85 | variable gas |
|---|
| 86 | |
|---|
| 87 | set gas(_${label}/entry) [$t get $node gas::entry] |
|---|
| 88 | set gas(_${label}/exit/ok) [$t get $node gas::exit::ok] |
|---|
| 89 | set gas(_${label}/exit/fail) [$t get $node gas::exit::fail] |
|---|
| 90 | |
|---|
| 91 | __Link $gas(_${label}/entry) $gas(cond) |
|---|
| 92 | /At ${label}/exit/ok |
|---|
| 93 | return |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | proc ::grammar::me::cpu::gasm::Cmd {cmd args} { |
|---|
| 97 | variable gas |
|---|
| 98 | |
|---|
| 99 | # Add a new instruction, and link it to the anchor. The created |
|---|
| 100 | # instruction becomes the new anchor. |
|---|
| 101 | |
|---|
| 102 | upvar 0 gas(grap) g gas(last) anchor gas(cond) cond |
|---|
| 103 | |
|---|
| 104 | set node [$g node insert] |
|---|
| 105 | $g node set $node instruction $cmd |
|---|
| 106 | $g node set $node arguments $args |
|---|
| 107 | |
|---|
| 108 | if {$anchor ne ""} {__Link $node $cond} |
|---|
| 109 | |
|---|
| 110 | set anchor $node |
|---|
| 111 | set cond always |
|---|
| 112 | return |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | proc ::grammar::me::cpu::gasm::Bra {} { |
|---|
| 116 | Cmd .BRA |
|---|
| 117 | } |
|---|
| 118 | |
|---|
| 119 | proc ::grammar::me::cpu::gasm::Nop {{text {}}} { |
|---|
| 120 | Cmd .NOP $text |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | proc ::grammar::me::cpu::gasm::Note {text} { |
|---|
| 124 | Cmd .C $text |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | proc ::grammar::me::cpu::gasm::Jmp {label} { |
|---|
| 128 | variable gas |
|---|
| 129 | __Link $gas(_$label) $gas(cond) |
|---|
| 130 | return |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | proc ::grammar::me::cpu::gasm::Exit {} { |
|---|
| 134 | variable gas |
|---|
| 135 | if {$gas(mode) eq "okfail"} { |
|---|
| 136 | __Link $gas(_exit/$gas(cond)) $gas(cond) |
|---|
| 137 | } else { |
|---|
| 138 | __Link $gas(_exit/return) always |
|---|
| 139 | } |
|---|
| 140 | return |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | proc ::grammar::me::cpu::gasm::Who {label} { |
|---|
| 144 | variable gas |
|---|
| 145 | return $gas(_$label) |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | proc ::grammar::me::cpu::gasm::__Link {to cond} { |
|---|
| 149 | variable gas |
|---|
| 150 | upvar 0 gas(grap) g gas(last) anchor |
|---|
| 151 | |
|---|
| 152 | set arc [$g arc insert $anchor $to] |
|---|
| 153 | $g arc set $arc condition $cond |
|---|
| 154 | return |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | proc ::grammar::me::cpu::gasm::/Label {name} { |
|---|
| 158 | variable gas |
|---|
| 159 | set gas(_$name) $gas(last) |
|---|
| 160 | return |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | proc ::grammar::me::cpu::gasm::/Clear {} { |
|---|
| 164 | variable gas |
|---|
| 165 | set gas(last) {} |
|---|
| 166 | set gas(cond) always |
|---|
| 167 | return |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | proc ::grammar::me::cpu::gasm::/Ok {} { |
|---|
| 171 | variable gas |
|---|
| 172 | set gas(cond) ok |
|---|
| 173 | return |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | proc ::grammar::me::cpu::gasm::/Fail {} { |
|---|
| 177 | variable gas |
|---|
| 178 | set gas(cond) fail |
|---|
| 179 | return |
|---|
| 180 | } |
|---|
| 181 | |
|---|
| 182 | proc ::grammar::me::cpu::gasm::/At {name} { |
|---|
| 183 | variable gas |
|---|
| 184 | set gas(last) $gas(_$name) |
|---|
| 185 | set gas(cond) always |
|---|
| 186 | return |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | proc ::grammar::me::cpu::gasm::/CloseLoop {} { |
|---|
| 190 | variable gas |
|---|
| 191 | $gas(grap) node set $gas(last) LOOP . |
|---|
| 192 | return |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | # ### ### ### ######### ######### ######### |
|---|
| 196 | ## Interfacing |
|---|
| 197 | |
|---|
| 198 | namespace eval grammar::me::cpu::gasm { |
|---|
| 199 | namespace export begin done lift state state! |
|---|
| 200 | namespace export Inline Cmd Bra Nop Note Jmp Exit Who |
|---|
| 201 | namespace export /Label /Clear /Ok /Fail /At /CloseLoop |
|---|
| 202 | } |
|---|
| 203 | |
|---|
| 204 | # ### ### ### ######### ######### ######### |
|---|
| 205 | ## Ready |
|---|
| 206 | |
|---|
| 207 | package provide grammar::me::cpu::gasm 0.1 |
|---|