# vim: set sw=3 tw=80: include "include/memory-map.txt" export read_char export write_char export newline export read_hex export write_hex export puts export end_of_monitor import decode_base64 start_of_monitor: _start: jump main include "lib/rs232.txt" to_upper: dup; immed 'a'; sub jump .not_lc rel lt drop dup; immed 'z'; sub jump .not_lc rel gt drop immed 32 sub return .not_lc: return start_str: byte "Stack CPU Monitor Program" 10 0 prompt_str: byte "> " 0 error_str: byte "ERROR" 10 0 access_str: byte "ACCESS DENIED" 10 0 # Commands: # READ addr # WRITE value addr # STORE start_addr # CALL addr main: immed start_str call puts .prompt: immed prompt_str call puts .getcmd: call read_char call to_upper dup; immed ' '; sub jump .ignore_sp rel eq drop dup; immed 10; sub jump .ignore_nl rel eq drop dup; immed 'R'; sub jump .read rel eq drop dup; immed 'W'; sub jump .write rel eq drop dup; immed 'S'; sub jump .store rel eq drop dup; immed 'C'; sub jump .call rel eq drop dup; immed 35; sub jump .comment rel eq drop drop .invalid: call newline immed error_str call puts jump .prompt .ignore_sp: jump .getcmd rel drop .ignore_nl: jump .prompt rel drop .expect_char: call read_char call to_upper sub jump .correct rel eq drop rdrop # Don't return to caller jump .invalid rel .correct: return .read: drop #R immed 'E'; call .expect_char rel immed 'A'; call .expect_char rel immed 'D'; call .expect_char rel immed ' '; call .expect_char rel call read_hex immed 10; sub jump ..invalid rel ne drop load call write_hex call newline jump .prompt rel ..invalid: jump .invalid rel drop .write: drop #W immed 'R'; call .expect_char rel immed 'I'; call .expect_char rel immed 'T'; call .expect_char rel immed 'E'; call .expect_char rel immed ' '; call .expect_char rel call read_hex immed ' '; sub jump ..invalid1 rel ne drop call read_hex immed 10; sub jump ..invalid2 rel ne drop dup; immed start_of_monitor; sub jump ..ok rel lt drop dup; immed end_of_monitor; sub jump ..denied rel lt drop ..ok: store jump .prompt ..invalid2: drop ..invalid1: jump .invalid rel drop ..denied: drop2 immed access_str call puts jump .prompt .store: drop #S immed 'T'; call .expect_char rel immed 'O'; call .expect_char rel immed 'R'; call .expect_char rel immed 'E'; call .expect_char rel immed ' '; call .expect_char rel call read_hex immed 10; sub jump ..invalid rel ne drop immed read_char immed .store_byte call decode_base64 drop2 jump .prompt rel ..invalid: jump .invalid rel drop .store_byte: # ( buffer byte -- buffer' ) over store byte immed 1 add return .call: drop #C immed 'A'; call .expect_char rel immed 'L'; call .expect_char rel immed 'L'; call .expect_char rel immed ' '; call .expect_char rel call read_hex immed 10; sub jump ..invalid rel ne drop call # expected: ( -- ) jump .prompt rel ..invalid: jump .invalid rel drop .comment: immed 10; sub jump .prompt eq drop call read_char jump .comment # Reads an arbitrary number of hex digits, returning the last eight as # a 32-bit integer along with the following non-hex character. read_hex: # ( -- integer last_char ) immed 0 call read_char call to_upper dup; push dup; immed '-'; sub jump .after_first_char rel ne drop .negative: drop .get_next_char: call read_char call to_upper .after_first_char: dup; immed '0'; sub jump .not_hex rel lt drop dup; immed '9'; sub jump .number rel le drop dup; immed 'A'; sub jump .not_hex rel lt drop dup; immed 'F'; sub jump .letter rel le drop .not_hex: swap pop; immed '-'; sub jump .positive rel ne drop immed 0; swap; sub .positive: swap return .number: immed '0'; sub .merge: push immed -4; rshift pop or jump .get_next_char rel .letter: immed 55; sub # 55 = 'A'-10 jump .merge rel # Displays integer as eight hex digits write_hex: # ( integer -- ) immed 8 .loop: push dup immed -4; rshift push immed 28; rshift dup; immed 10; sub jump .letter rel ge drop immed '0' .common: add call write_char jump .next rel .letter: immed 10; sub immed 'A' jump .common rel .next: pop pop immed 1; sub jump .loop rel gt drop2 return include "lib/base64.txt" # ( addr -- ) [ addr -> null-terminated ASCII string ] puts: dup load byte jump .nul rel eq call write_char immed 1 add jump puts rel .nul: drop2 return end_of_monitor: