You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

681 lines
13 KiB

2 years ago
.include "instr.inc"
.text
mem_e000:
.2byte 0
mem_e002:
.fill 0x0efe
mem_ef00:
.fill 0xb0
mem_efb0:
.fill 0x30
mem_efe0:
.fill 0x20
.global _start
_start:
ld_sp stack
# Set up the entrypoint for the breakpoint instruction
ld_r0 entry
ld_r1 0x98 # 'call'
strb_r1_r0
inc_r0
ld_r1 main
str_r1_r0
# Explain the debugger
ld_r2 str_intro
call PrintStr
# Execute the breakpoint, jump to main
brk
# If breakpoint returns here, we've ran out of stack
ld_r2 str_dry_stack
call PrintStr
copr_halt
die:
jp die
main:
# Save all the registers
push_sp
str_r0 mem_save_r0
str_r1 mem_save_r1
str_r2 mem_save_r2
str_r3 mem_save_r3
# Store the stack pointer
pop_r0
str_r0 mem_info_sp
# Read the return address
ld_r0_sp
ldr_r0_r0
add_r0 -1
str_r0 mem_info_pc
# Read some more stack values
ld_r1 (6 * 2)
ld_r2 mem_info_stack
ldr_r3 mem_info_sp
call MemCpy
# Print the processor state
ld_r2 str_breakpoint
call PrintStr
main_cmd_loop:
ld_r0 0
strb_r0 mem_e002
ld_r2 str_ready
call PrintStr
# Read input
ld_r2 mem_e000
ld_r3 8
call ReadStr
cp_r3 0
jp_eq error_too_long
ld_r2 mem_e000
call StrTrim
# Make sure the input is at most 2 characters
ldrb_r0 mem_e002
cp_r0 0
jp_ne error_bad_command
# Parse all the commands
ldr_r0 mem_e000
cp_r0 ('h' + '\n' * 0x100)
jp_eq cmd_help
cp_r0 'h'
jp_eq cmd_help
cp_r0 'r'
jp_eq cmd_read
cp_r0 ('r' + '\n' * 0x100)
jp_eq cmd_read
cp_r0 'p'
jp_eq cmd_print
cp_r0 ('p' + '\n' * 0x100)
jp_eq cmd_print
cp_r0 'x'
jp_eq cmd_exec
cp_r0 ('x' + '\n' * 0x100)
jp_eq cmd_exec
cp_r0 'c'
jp_eq cmd_cont
cp_r0 ('c' + '\n' * 0x100)
jp_eq cmd_cont
cp_r0 ('U' + 'C' * 0x100)
jp_eq cmd_undoc
cp_r0 ('l' + 's' * 0x100)
jp_eq cmd_list
cp_r0 ('r' + 'f' * 0x100)
jp_eq cmd_readfile
cp_r0 'w'
jp_eq cmd_write
cp_r0 ('w' + '\n' * 0x100)
jp_eq cmd_write
error_bad_command:
ld_r2 str_error_bad_command
call PrintStr
jp main_cmd_loop
error_too_long:
ld_r2 str_error_too_long
call PrintStr
jp main_cmd_loop
cmd_help:
ld_r2 str_help
call PrintStr
jp main_cmd_loop
cmd_read:
# Get the address to read
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
cp_r0 -1
jp_eq cmd_read_invalid
push_r0
# Get the amount of lines to read
ld_r2 str_prompt_lines
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
cp_r0 -1
jp_eq cmd_read_invalid
cp_r0 0
jp_eq cmd_read_invalid
# r2 = address, r3 = lines
ld_r3_r0
pop_r2
cmd_read_loop:
# Read 8 bytes
push_r2
push_r3
ld_r1 8
ld_r3_r2
ld_r2 mem_data
call MemCpy
pop_r3
pop_r2
# Store the current read address
str_r2 mem_addr
# Write it out
push_r2
push_r3
ld_r2 str_hexdump
call PrintStr
pop_r3
pop_r2
# Check if we're done
add_r2 8
dec_r3
cp_r3 0
jp_ne cmd_read_loop
jp main_cmd_loop
cmd_read_invalid:
ld_r2 str_error_invalid_input
call PrintStr
jp main_cmd_loop
cmd_write:
# Get the address to write
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
cp_r0 -1
jp_eq cmd_write_invalid
str_r0 mem_addr
ld_r2 str_prompt_hex
call PrintStr
cmd_write_loop:
# Clear the buffer
ld_r3 mem_e000 + 2
ld_r0 0
strb_r0_r3
dec_r3
strb_r0_r3
dec_r3
cmd_write_loop_first:
# Get the first nybble
copr_getc
strb_r0_r3
ld_r2_r3
# Check if it's the end or invalid
cp_r0 '.'
jp_eq cmd_write_end
cp_r0 '\n'
jp_eq cmd_write_loop_first
# Try to convert the nybble
push_r3
call ConvertHex
pop_r3
cp_r0 -1
jp_eq cmd_write_loop_first
inc_r3
cmd_write_loop_second:
# Get the second nybble
copr_getc
strb_r0_r3
ld_r2_r3
# Check if it's the end or invalid
cp_r0 '.'
jp_eq cmd_write_end
cp_r0 '\n'
jp_eq cmd_write_loop_second
# Try to convert the nybble
push_r3
call ConvertHex
pop_r3
cp_r0 -1
jp_eq cmd_write_loop_second
# Convert and store the full byte
dec_r3
ld_r2_r3
call ConvertHex
ldr_r1 mem_addr
strb_r0_r1
inc_r1
str_r1 mem_addr
jp cmd_write_loop # 0xf1d0
cmd_write_end:
# Read until newline
copr_getc
cp_r0 '\n'
jp_ne cmd_write_end
ld_r2 str_loaded
call PrintStr
jp main_cmd_loop
cmd_write_invalid:
ld_r2 str_error_invalid_input
call PrintStr
jp main_cmd_loop
cmd_print:
# Get the string to print
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
ld_r2_r0
call PrintStr
jp main_cmd_loop
cmd_exec:
# Get the address to execute
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
# Prompt the user to execute the address
push_r0
str_r0 mem_addr
ld_r2 str_prompt_exec
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ldrb_r0 mem_e000
cp_r0 'Y'
jp_eq cmd_exec_go
cp_r0 'y'
jp_eq cmd_exec_go
# Cancel the call
ld_r2 str_error_cancelled
call PrintStr
pop_r0
jp main_cmd_loop
cmd_exec_go:
# Call the function
pop_r3
call_r3
jp main_cmd_loop
cmd_cont:
ld_r2 str_continuing
call PrintStr
# Restore register state and unpause
ldr_r0 mem_save_r0
ldr_r1 mem_save_r1
ldr_r2 mem_save_r2
ldr_r3 mem_save_r3
ret
cmd_list:
ld_r2 str_file_list_header
call PrintStr
# Read directory
ld_r0 0
ld_r1 mem_e000
copr_readblk
ld_r3 mem_e000
cmd_list_loop:
ldrb_r0_r3
cp_r0 0
jp_eq cmd_list_next
# Store block
push_r3
strb_r0 mem_data
inc_r3
ldr_r0_r3
# Store size
push_r3
str_r0 mem_addr
# Print block and size
ld_r2 str_file_list_entry
call PrintStr
pop_r3
# Print filename
inc_r3
inc_r3
ld_r2_r3
call PrintStr
ld_r0 '\n'
copr_putc
pop_r3
cmd_list_next:
add_r3 0x10
cp_r3 mem_ef00
jp_ne cmd_list_loop
jp main_cmd_loop
cmd_undoc:
ld_r2 str_undoc
call PrintStr
jp main_cmd_loop
cmd_readfile:
ld_r2 str_prompt_filename
call PrintStr
# Read directory
ld_r0 0
ld_r1 mem_e000
copr_readblk
# Get filename to read
ld_r2 mem_efb0
ld_r3 0x10
call ReadStr
cp_r3 0
jp_eq cmd_readfile_error_too_long
ld_r2 mem_efb0
call StrTrim
ld_r3 mem_e000 + 3
cmd_readfile_loop:
# Check if the filename matches
ld_r2 mem_efb0
push_r3
call StrCmp
pop_r3
cp_r0 0
jp_eq cmd_readfile_match
add_r3 0x10
cp_r3 mem_ef00 + 3
jp_eq cmd_readfile_error_not_found
jp cmd_readfile_loop
cmd_readfile_match:
# Read file block
dec_r3
dec_r3
dec_r3
ldrb_r0_r3
# Read file size
inc_r3
ldr_r1_r3
# Read file into memory
push_r1
ld_r1 mem_e000
copr_readblk
# Prompt for address to write to
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_efe0
ld_r3 0x10
call ReadStr
ld_r2 mem_efe0
call ConvertHex
pop_r1
cp_r0 -1
jp_eq cmd_readfile_error_invalid_input
# Copy the data
ld_r2_r0
ld_r3 mem_e000
call MemCpy
ld_r2 str_loaded
call PrintStr
jp main_cmd_loop
cmd_readfile_error_not_found:
ld_r2 str_error_not_found
call PrintStr
jp main_cmd_loop
cmd_readfile_error_too_long:
ld_r2 str_error_too_long
call PrintStr
jp main_cmd_loop
cmd_readfile_error_invalid_input:
ld_r2 str_error_invalid_input
call PrintStr
jp main_cmd_loop
str_intro:
.ascii "======================================================================\n"
.ascii "Welcome to Glitch Research Laboratory Network: Test Server 1 (GRLTS01)\n"
.ascii "======================================================================\n"
.ascii "GRLTS01 is intended for research purposes only, to aid our engineers\n"
.ascii "in migrating their software to the latest GLVM architecture.\n"
.ascii "This server will boot into a machine language monitor, providing\n"
.ascii "a simple environment for development and testing.\n"
.ascii "\n"
.ascii "Note that this server is publicly accessible, and thus, should never\n"
.ascii "be used to store any confidential information. If storage of data is\n"
.ascii "necessary, consider utilizing encryption, or using our dedicated\n"
.ascii "storage servers GRLFS01.\n"
.ascii "Additionally, consider using GRLTS02 for any serious work - it's\n"
.ascii "an authenticated test server, which should be far more secure.\n"
.ascii "======================================================================\n"
.ascii "Running machine language monitor now.\n"
.ascii "======================================================================\n"
.ascii "\n\0"
str_error_too_long:
.ascii "! Input too long error.\n\0"
str_error_bad_command:
.ascii "! Bad command error (h for help).\n\0"
str_error_invalid_input:
.ascii "! Invalid input error.\n\0"
str_prompt_address:
.ascii "> Which address? \0"
str_prompt_lines:
.ascii "> How many lines? \0"
str_prompt_exec:
.ascii "> Really exec at "
text_ram_word mem_addr
.ascii "? Type Y if so: \0"
str_error_cancelled:
.ascii "! Cancelled action error.\n\0"
str_continuing:
.ascii "Continuing.\n\0"
str_loaded:
.ascii "Loaded.\n\0"
str_dry_stack:
.ascii "! Dry stack. Halting machine.\n\0"
str_prompt_filename:
.ascii "> Filename? \0"
str_error_not_found:
.ascii "! File not found error.\n\0"
str_prompt_hex:
.ascii "> Enter hex data. End with dot \".\" + newline:\n\0"
str_undoc:
.ascii "Wow, undocumented monitor command! FOOLS2023_{Secret"
text_ram_word 0xe000
.ascii "x"
text_ram_word 0xe001
.ascii "Command}\n\0"
str_help:
.ascii "Available commands:\n"
.ascii "r :: print memory as hex\n"
.ascii "p :: print memory as text\n"
.ascii "w :: write hex data to memory\n"
.ascii "x :: execute memory\n"
.ascii "rf :: load memory from file\n"
.ascii "ls :: print file index\n"
.ascii "h :: print this help message\n"
.ascii "c :: exit monitor and continue\n"
.ascii "Please enter hex numbers when prompted.\n"
.ascii "If necessary for debugging, you can break into monitor\n"
.ascii "with instruction BRK (0x00) and continue with 'c'\n"
.ascii "Note: memory region E000-FFFF is used by monitor\n\0"
str_file_list_header:
.ascii "BLK SIZE NAME\n"
.ascii "=======================\n\0"
str_file_list_entry:
text_ram_byte mem_data
.ascii " "
text_ram_word mem_addr
.ascii " \0" # 0xfa97
str_ready:
.ascii "Ready.\n"
.ascii "> \0"
str_breakpoint:
.ascii "*** BREAK INTO MONITOR AT $"
text_ram_word mem_info_pc
.ascii " ***\n"
.ascii "R0=$"
text_ram_word mem_save_r0
.ascii " R1=$"
text_ram_word mem_save_r1
.ascii " R2=$"
text_ram_word mem_save_r2
.ascii " R3=$"
text_ram_word mem_save_r3
.ascii "\n"
.ascii "SP=$"
text_ram_word mem_info_sp
.ascii " ["
text_ram_byte mem_info_stack + 0
text_ram_byte mem_info_stack + 1
text_ram_byte mem_info_stack + 2
text_ram_byte mem_info_stack + 3
text_ram_byte mem_info_stack + 4
text_ram_byte mem_info_stack + 5
text_ram_byte mem_info_stack + 6
text_ram_byte mem_info_stack + 7
text_ram_byte mem_info_stack + 8
text_ram_byte mem_info_stack + 9
text_ram_byte mem_info_stack + 10
text_ram_byte mem_info_stack + 11
.ascii "]\n\0"
str_hexdump:
text_ram_word mem_addr
.ascii " | "
text_ram_byte mem_data + 0
.ascii " "
text_ram_byte mem_data + 1
.ascii " "
text_ram_byte mem_data + 2
.ascii " "
text_ram_byte mem_data + 3
.ascii " "
text_ram_byte mem_data + 4
.ascii " "
text_ram_byte mem_data + 5
.ascii " "
text_ram_byte mem_data + 6
.ascii " "
text_ram_byte mem_data + 7
.ascii "\n\0"
mem_save_r0:
.2byte 0
mem_save_r1:
.2byte 0
mem_save_r2:
.2byte 0
mem_save_r3:
.2byte 0
mem_info_sp:
.2byte 0
mem_info_pc:
.2byte 0
mem_info_stack:
.fill 12
mem_data:
.fill 8
mem_addr:
.2byte 0
.fill 0xf00 - (. - _start)
stack:
.fill 0xf0
entry:
.fill 0x10