[0.2.1575] - UI Greatly improved + Debugger functionality added
This commit is contained in:
parent
758b1e41b8
commit
42f25f4e0b
30 changed files with 1857 additions and 757 deletions
|
|
@ -2,7 +2,7 @@
|
|||
#-----------------------------------------------------------------------------------------
|
||||
set(PROJ_NAME DragonVM)
|
||||
set(MAJOR_VER 0)
|
||||
set(MINOR_VER 1)
|
||||
set(MINOR_VER 2)
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
#Setup
|
||||
|
|
@ -72,6 +72,7 @@ list(APPEND ASSEMBLER_SOURCE_FILES
|
|||
list(APPEND TOOLS_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/tools_main.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/Utils.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/Tools.cpp
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualHardDrive.cpp
|
||||
)
|
||||
|
|
@ -115,8 +116,8 @@ if (WIN32)
|
|||
target_link_libraries(${TOOLS_TARGET} mingw32)
|
||||
target_link_libraries(${DEBUGGER_TARGET} mingw32)
|
||||
endif (WIN32)
|
||||
target_link_libraries(${RUNTIME_TARGET} SDL2main SDL2 SDL2_mixer SDL2_image)
|
||||
target_link_libraries(${DEBUGGER_TARGET} SDL2main SDL2 SDL2_mixer SDL2_image)
|
||||
target_link_libraries(${RUNTIME_TARGET} SDL2main SDL2)
|
||||
target_link_libraries(${DEBUGGER_TARGET} SDL2main SDL2)
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
#Linking
|
||||
|
|
|
|||
2
build.nr
2
build.nr
|
|
@ -1 +1 @@
|
|||
1544
|
||||
1576
|
||||
|
|
|
|||
|
|
@ -7,33 +7,35 @@ rm -r ./win-release
|
|||
cd bin
|
||||
|
||||
printf "${green}Compiling vBIOS...\n${clear}"
|
||||
./dasm dss/bios.dss -o dragon/bios.bin --save-disassembly disassembly/bios.dds
|
||||
./dasm dss/bios.dss -o dragon/bios.bin --save-disassembly disassembly/bios.dds --verbose
|
||||
|
||||
printf "\n${green}Creating Virtual Disk...\n${clear}"
|
||||
rm dragon/disk1.dr
|
||||
./dtools new-vdisk dragon/disk1.dr 1048576
|
||||
|
||||
printf "\n${green}Compiling MBR Block...\n${clear}"
|
||||
./dasm dss/mbr.dss -o dragon/mbr.bin --save-disassembly disassembly/mbr.dds
|
||||
./dasm dss/mbr.dss -o dragon/mbr.bin --save-disassembly disassembly/mbr.dds --verbose
|
||||
|
||||
printf "\n${green}Loading MBR Block...\n${clear}"
|
||||
./dtools load-program dragon/disk1.dr dragon/mbr.bin 0x00000000
|
||||
./dtools load-binary dragon/disk1.dr dragon/mbr.bin 0x00000000
|
||||
|
||||
printf "${green}Compiling Test Program...\n"
|
||||
./dasm dss/test.dss -o test.bin --save-disassembly disassembly/test.dds
|
||||
./dasm dss/test.dss -o test.bin --save-disassembly disassembly/test.dds --verbose
|
||||
|
||||
printf "${green}Creating Windows Release...\n"
|
||||
cd ..
|
||||
mkdir win-release
|
||||
mkdir win-release/disassembly
|
||||
cp ./bin/dasm.exe ./win-release
|
||||
cp ./bin/ddb.exe ./win-release
|
||||
cp ./bin/dtools.exe ./win-release
|
||||
cp ./bin/dvm.exe ./win-release
|
||||
cp ./bin/font.bmp ./win-release
|
||||
cp ./bin/test.bin ./win-release
|
||||
# cp ./bin/test.bin ./win-release
|
||||
|
||||
cp -r ./bin/config ./win-release
|
||||
cp -r ./bin/disassembly ./win-release
|
||||
cp -r ./bin/disassembly/bios.dds ./win-release/disassembly
|
||||
cp -r ./bin/disassembly/mbr.dds ./win-release/disassembly
|
||||
cp -r ./bin/dragon ./win-release
|
||||
|
||||
mkdir ./win-release/dss
|
||||
|
|
@ -48,8 +50,3 @@ cp C:/msys64/ucrt64/bin/SDL2.dll ./win-release
|
|||
cp C:/msys64/ucrt64/bin/libostd.dll ./win-release
|
||||
|
||||
cp ./run-test.bat ./win-release
|
||||
|
||||
typeset -i build_number=$(cat build.nr)
|
||||
((build_number++))
|
||||
truncate -s 0 build.nr
|
||||
echo $build_number >> build.nr
|
||||
Binary file not shown.
|
|
@ -1,41 +1,42 @@
|
|||
## ============================= Memory Mapped Devices and Registers =============================
|
||||
@define MBR_START_ADDRESS 0x1380
|
||||
@define INT_VEC_START_ADDRESS 0x1080
|
||||
@define DISK_INTERFACE_START_ADDRESS 0x1580
|
||||
@define MEMORY_START_ADDRESS 0x1740
|
||||
@define CMOS_START_ADDRESS 0x1000
|
||||
## ===============================================================================================
|
||||
@group MemoryAddresses
|
||||
MBR 0x1380
|
||||
INT_VEC 0x1080
|
||||
DISK_INTERFACE 0x1580
|
||||
RAM 0x1740
|
||||
CMOS 0x1000
|
||||
@end
|
||||
|
||||
@define _CMOS_REG_BOOT_DISK {CMOS_START_ADDRESS + 0x0010}
|
||||
@group CMOS_Settings
|
||||
BOOT_DISK {MemoryAddresses.CMOS + 0x0010}
|
||||
@end
|
||||
## ===============================================================================================
|
||||
|
||||
.load 0x0000 ## BIOS is mapped to address 0x0000 in memory
|
||||
.data
|
||||
$bios_version_number 0x04, 0x01 ## BIOS Version stored in memory
|
||||
$bios_version_number 0x00, 0x01 ## BIOS Version stored in memory
|
||||
|
||||
## ============================= BIOS Program =============================
|
||||
.code
|
||||
## mov FL, 0
|
||||
## jmp 0x1740
|
||||
mov FL, 0b0000000000000001 ## Zero the FL Register and enable interrupts
|
||||
movb [{INT_VEC_START_ADDRESS + (0x20 * 3)}], 0xFF ## Setting up int 0x20 handler
|
||||
mov [{INT_VEC_START_ADDRESS + (0x20 * 3) + 1}], $_int_20_handler ## --
|
||||
movb [{MemoryAddresses.INT_VEC + (0x20 * 3)}], 0xFF ## Setting up int 0x20 handler
|
||||
mov [{MemoryAddresses.INT_VEC + (0x20 * 3) + 1}], $_int_20_handler ## --
|
||||
|
||||
mov R10, 0x00 ## Setting up int 0x30 handler by using int 0x20 functionality
|
||||
mov R9, $_int_30_handler ## -Passing the handler's address
|
||||
mov R8, 0x30 ## -Passing the interrupt's code to setup
|
||||
int 0x20 ## -Calling int 0x20 with 0x00 as parameter, to set new handler up
|
||||
|
||||
## TODO: Probably move this code before interrupts are enabled
|
||||
## to prevent an interrupt being fired while loading MBR
|
||||
## data from disk
|
||||
## ----
|
||||
## MBR Loading
|
||||
and FL, 0b1111111111111110 ## Disable interrupts
|
||||
push 0
|
||||
call $_load_mbr_data_block
|
||||
or FL, 0b0000000000000001 ## Enable interrupts
|
||||
## ----
|
||||
|
||||
debug_break
|
||||
jmp MBR_START_ADDRESS ## Jump to start of MBR in memory
|
||||
jmp MemoryAddresses.MBR ## Jump to start of MBR in memory
|
||||
hlt ## Just in case somehow execution reaches this point
|
||||
## ========================================================================
|
||||
|
||||
|
|
@ -49,21 +50,21 @@ _int_20_handler:
|
|||
jeq $_int_20_clear_interrupt, 0x0001
|
||||
jmp $_int_20_end
|
||||
_int_20_disk_interface:
|
||||
movb [{DISK_INTERFACE_START_ADDRESS + 0x1}], *R9 ## Mode
|
||||
movb [{MemoryAddresses.DISK_INTERFACE + 0x1}], *R9 ## Mode
|
||||
inc R9
|
||||
movb [{DISK_INTERFACE_START_ADDRESS + 0x2}], *R9 ## Disk
|
||||
movb [{MemoryAddresses.DISK_INTERFACE + 0x2}], *R9 ## Disk
|
||||
inc R9
|
||||
mov [{DISK_INTERFACE_START_ADDRESS + 0x3}], *R9 ## Sector
|
||||
mov [{MemoryAddresses.DISK_INTERFACE + 0x3}], *R9 ## Sector
|
||||
inc R9
|
||||
inc R9
|
||||
mov [{DISK_INTERFACE_START_ADDRESS + 0x5}], *R9 ## Address
|
||||
mov [{MemoryAddresses.DISK_INTERFACE + 0x5}], *R9 ## Address
|
||||
inc R9
|
||||
inc R9
|
||||
mov [{DISK_INTERFACE_START_ADDRESS + 0x7}], *R9 ## Size
|
||||
mov [{MemoryAddresses.DISK_INTERFACE + 0x7}], *R9 ## Size
|
||||
inc R9
|
||||
inc R9
|
||||
mov [{DISK_INTERFACE_START_ADDRESS + 0x9}], *R9 ## Memory Address
|
||||
movb [DISK_INTERFACE_START_ADDRESS], 0x00 ## Signal set to "Start Operation"
|
||||
mov [{MemoryAddresses.DISK_INTERFACE + 0x9}], *R9 ## Memory Address
|
||||
movb [MemoryAddresses.DISK_INTERFACE], 0x00 ## Signal set to "Start Operation"
|
||||
jmp $_int_20_end
|
||||
_int_20_set_new_interrupt_handler:
|
||||
push R8 ## Interrupt Code
|
||||
|
|
@ -93,36 +94,34 @@ _int_30_end:
|
|||
|
||||
|
||||
_load_mbr_data_block:
|
||||
movb [{DISK_INTERFACE_START_ADDRESS + 0x1}], 0x00 ## Mode = Read
|
||||
movb R1, [_CMOS_REG_BOOT_DISK]
|
||||
movb [{DISK_INTERFACE_START_ADDRESS + 0x2}], R1 ## Disk = Default
|
||||
mov [{DISK_INTERFACE_START_ADDRESS + 0x3}],0x0000 ## Sector = 0x0000
|
||||
mov [{DISK_INTERFACE_START_ADDRESS + 0x5}],0x0000 ## Address = 0x0000 (Start of Disk)
|
||||
mov [{DISK_INTERFACE_START_ADDRESS + 0x7}], 20 ## Size = 512 (Size of MBR is 512 bytes)
|
||||
mov [{DISK_INTERFACE_START_ADDRESS + 0x9}], MBR_START_ADDRESS ## MemoryAddress = MBR Address in memory
|
||||
movb [DISK_INTERFACE_START_ADDRESS], 0x00 ## Signal = Start
|
||||
movb [{MemoryAddresses.DISK_INTERFACE + 0x1}], 0x00 ## Mode = Read
|
||||
movb R1, [CMOS_Settings.BOOT_DISK]
|
||||
movb [{MemoryAddresses.DISK_INTERFACE + 0x2}], R1 ## Disk = Default
|
||||
mov [{MemoryAddresses.DISK_INTERFACE + 0x3}],0x0000 ## Sector = 0x0000
|
||||
mov [{MemoryAddresses.DISK_INTERFACE + 0x5}],0x0000 ## Address = 0x0000 (Start of Disk)
|
||||
mov [{MemoryAddresses.DISK_INTERFACE + 0x7}], 512 ## Size = 512 (Size of MBR is 512 bytes)
|
||||
mov [{MemoryAddresses.DISK_INTERFACE + 0x9}], MemoryAddresses.MBR ## MemoryAddress = MBR Address in memory
|
||||
movb [MemoryAddresses.DISK_INTERFACE], 0x00 ## Signal = Start
|
||||
_load_mbr_data_block_wait_loop:
|
||||
mov ACC, [{DISK_INTERFACE_START_ADDRESS + 0xB}] ## Moving <Status> register into ACC
|
||||
mov ACC, [{MemoryAddresses.DISK_INTERFACE + 0xB}] ## Moving <Status> register into ACC
|
||||
jne $_load_mbr_data_block_wait_loop, 0x00 ## If <Status> register not Free, loop around and wait
|
||||
ret
|
||||
|
||||
_calc_interrupt_vector_address:
|
||||
mov R1, *PP
|
||||
arg R1
|
||||
mul R1, 0x03 ## Multiply the interrupt code by 3 for memory alignment
|
||||
mov R1, ACC
|
||||
add R1, INT_VEC_START_ADDRESS ## Add Interrupt Vector base address to Interrupt code
|
||||
add R1, MemoryAddresses.INT_VEC ## Add Interrupt Vector base address to Interrupt code
|
||||
mov RV, ACC
|
||||
ret
|
||||
|
||||
_set_interrupt_vector_entry:
|
||||
mov R1, *PP
|
||||
arg R1
|
||||
push R1
|
||||
push 1
|
||||
call $_calc_interrupt_vector_address
|
||||
mov R1, RV
|
||||
dec PP
|
||||
dec PP
|
||||
mov ACC, *PP
|
||||
arg ACC
|
||||
jeq $_set_interrupt_vector_entry_disable, 0x0000
|
||||
movb *R1, 0xFF
|
||||
jmp $_set_interrupt_vector_entry_end
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
.load 0x1740
|
||||
|
||||
##@struct Rectangle {
|
||||
## width:2,
|
||||
## height:2,
|
||||
## x:2,
|
||||
## y:2
|
||||
##
|
||||
## ## Static properties
|
||||
## StructSize
|
||||
##}
|
||||
|
||||
.data
|
||||
$cursor_pos 0x00, 0x00
|
||||
$color 0x02
|
||||
$current_video_addr 0x07, 0xBC
|
||||
|
||||
$string "Hello World!!"
|
||||
|
||||
## $rect => Rectangle
|
||||
|
||||
.code
|
||||
infinite_loop:
|
||||
push 0
|
||||
call $clear_screen
|
||||
|
||||
## mov $rect.x, 200
|
||||
|
||||
|
||||
push $string
|
||||
push 1
|
||||
call $print_string
|
||||
|
||||
jmp $infinite_loop
|
||||
hlt
|
||||
|
||||
|
||||
print_string:
|
||||
mov R1, *PP
|
||||
dec PP
|
||||
dec PP
|
||||
|
||||
push R1
|
||||
push 1
|
||||
call $strlen
|
||||
mov R2, RV
|
||||
|
||||
push 65
|
||||
push 1
|
||||
call $print_char
|
||||
ret
|
||||
|
||||
|
||||
strlen:
|
||||
mov R1, *PP
|
||||
dec PP
|
||||
dec PP
|
||||
mov R2, 0
|
||||
_strlen_loop:
|
||||
movb ACC, *R1
|
||||
jeq $_strlen_end_loop, 0
|
||||
inc R2
|
||||
inc R1
|
||||
jmp $_strlen_loop
|
||||
_strlen_end_loop:
|
||||
mov RV, R2
|
||||
ret
|
||||
|
||||
print_char:
|
||||
mov R2, *PP
|
||||
dec PP
|
||||
dec PP
|
||||
mov R1, [$current_video_addr]
|
||||
mov R3, [$cursor_pos]
|
||||
mul R3, 2
|
||||
mov R3, ACC
|
||||
add R1, R3
|
||||
mov R1, ACC
|
||||
movb *R1, R2
|
||||
inc R1
|
||||
movb *R1, [$color]
|
||||
mov R3, [$cursor_pos]
|
||||
inc R3
|
||||
mov [$cursor_pos], R3
|
||||
ret
|
||||
|
||||
clear_screen:
|
||||
mov R10, 0x00
|
||||
int 0x30
|
||||
ret
|
||||
|
||||
.fixed 512, 0x00
|
||||
|
|
@ -1,74 +1,80 @@
|
|||
.load 0x1740
|
||||
|
||||
.data
|
||||
$cursor_pos 0x00, 0x00
|
||||
$color 0x02
|
||||
$current_video_addr 0x07, 0xBC
|
||||
@struct Rectangle
|
||||
width:2 > 0x11, 0x22
|
||||
height:2 > 0x99
|
||||
x:2
|
||||
y:2 > 0xAA
|
||||
@end
|
||||
|
||||
.data
|
||||
$string "Hello World!!"
|
||||
$rect <Rectangle> = (0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88)
|
||||
$test_byte 0xAF
|
||||
$super_long_variable_name 0x01, 0x02, 0x03, 0x04
|
||||
|
||||
.code
|
||||
debug_break
|
||||
infinite_loop:
|
||||
begin:
|
||||
mov R10, Rectangle.SIZE
|
||||
mov R9, [$rect.height]
|
||||
mov R8, [$rect.width]
|
||||
mov R7, [$rect.x]
|
||||
mov R5, $strlen
|
||||
push $string
|
||||
push 1
|
||||
call R5
|
||||
push 0
|
||||
call $clear_screen
|
||||
|
||||
jmp $infinite_loop
|
||||
call $testinttest
|
||||
debug_break
|
||||
mov [$rect.y], 0x0000
|
||||
## debug_break
|
||||
jmp $begin
|
||||
push $string
|
||||
push 1
|
||||
call $strlen
|
||||
mov R1, RV
|
||||
mov IP, 0x0001
|
||||
mov R1, RV
|
||||
hlt
|
||||
|
||||
|
||||
print_string:
|
||||
mov R1, *PP
|
||||
dec PP
|
||||
dec PP
|
||||
testinttest:
|
||||
push 0
|
||||
call $inttest
|
||||
ret
|
||||
|
||||
push R1
|
||||
push 1
|
||||
call $strlen
|
||||
mov R2, RV
|
||||
inttest:
|
||||
push 0
|
||||
call $testint
|
||||
ret
|
||||
|
||||
push 65
|
||||
push 1
|
||||
call $print_char
|
||||
testint:
|
||||
push 0
|
||||
call $test_int
|
||||
ret
|
||||
|
||||
test_int:
|
||||
push 0
|
||||
call $int_test
|
||||
ret
|
||||
|
||||
int_test:
|
||||
nop
|
||||
ret
|
||||
|
||||
|
||||
strlen:
|
||||
mov R1, *PP
|
||||
dec PP
|
||||
dec PP
|
||||
arg R1
|
||||
mov R2, 0
|
||||
_strlen_loop:
|
||||
loop:
|
||||
movb ACC, *R1
|
||||
jeq $_strlen_end_loop, 0
|
||||
inc R2
|
||||
inc R1
|
||||
jmp $_strlen_loop
|
||||
_strlen_end_loop:
|
||||
jeq $loop_end, 0
|
||||
not_zero:
|
||||
inc R2
|
||||
jmp $loop
|
||||
loop_end:
|
||||
mov RV, R2
|
||||
ret
|
||||
|
||||
print_char:
|
||||
mov R2, *PP
|
||||
dec PP
|
||||
dec PP
|
||||
mov R1, [$current_video_addr]
|
||||
mov R3, [$cursor_pos]
|
||||
mul R3, 2
|
||||
mov R3, ACC
|
||||
add R1, R3
|
||||
mov R1, ACC
|
||||
movb *R1, R2
|
||||
inc R1
|
||||
movb *R1, [$color]
|
||||
mov R3, [$cursor_pos]
|
||||
inc R3
|
||||
mov [$cursor_pos], R3
|
||||
ret
|
||||
|
||||
clear_screen:
|
||||
mov R10, 0x00
|
||||
int 0x30
|
||||
ret
|
||||
|
||||
.fixed 512, 0x00
|
||||
|
|
@ -1,8 +1,101 @@
|
|||
.load 0x1740
|
||||
##=================================================================================================================================
|
||||
## This is the test program for the Dragon Virtual Machine. The example has two subroutines: One is the $strlen subroutine,
|
||||
## which calculates the length of the string passed as a parameter; The other calculates the fibonacci sequence up to the
|
||||
## Nth number (N being the parameter passed to the subroutine).
|
||||
## In the main part of the .code section, debug_break instructions are used in order to pause the debugger, so that the
|
||||
## results can be seen, since there is no Virtual Display implemented yet in the Dragon Runtime (that's the next thing to come).
|
||||
##=================================================================================================================================
|
||||
|
||||
|
||||
.load 0x1740 ## The program is loaded at address 0x1740, which is the first address of normal RAM
|
||||
|
||||
##=================================================================================================================================
|
||||
## This is the data section, used to declare variables that will be stored inside the application space
|
||||
##=================================================================================================================================
|
||||
.data
|
||||
$hello_world_str "Hello World!!" ## In the data section only, you can declare a stream of bytes as a
|
||||
## string literal between double-quotes. The assembler will convert
|
||||
## it into the corresponding bytes, and will add a 0 byte at the end
|
||||
## as the null termination.
|
||||
$n1 0x00, 0x00 ## Other data declared in the data section must be represented as a
|
||||
$n2 0x00, 0x01 ## comma-separated series of bytes (except for string literals - see
|
||||
$n3 0x00, 0x01 ## above). No size data is stored for byte streams.
|
||||
##=================================================================================================================================
|
||||
|
||||
|
||||
|
||||
##=================================================================================================================================
|
||||
## This is the start of the .code section, and it acts as the entry point for the program
|
||||
##=================================================================================================================================
|
||||
.code
|
||||
mov R1, 0xABCD
|
||||
debug_break
|
||||
hlt
|
||||
push $hello_world_str ## Push the address of the first character of the $hello_world_str string to the stack
|
||||
push 1 ## Push the number 1 to the stack, as the number of arguments for the next call instruction
|
||||
call $strlen ## Call the $strlen subroutine
|
||||
mov R1, RV ## Load the return value into the R1 register
|
||||
debug_break ## This debug break is here for the debugger to pause, in order to see the results of
|
||||
## the function call in the debugger, since the Virtual Display is not implemented yet.
|
||||
push 25 ## Push the number 25 as a parameter to the $fibonacci subroutine, so that it will
|
||||
## calculate up to the 25th fibonacci value, which is the maximum for 16-bits.
|
||||
push 1 ## Push the number 1 to the stack, as the number of arguments for the next call instruction
|
||||
call $fibonacci ## Call the $fibonacci subroutine
|
||||
mov R2, RV ## Load the return value into the R2 register
|
||||
debug_break ## This debug break is here for the debugger to pause, in order to see the results of
|
||||
## the function call in the debugger, since the Virtual Display is not implemented yet.
|
||||
hlt ## This is the halt instruction, and it stops the CPU of the Virtual Machine.
|
||||
##=================================================================================================================================
|
||||
|
||||
.fixed 512, 0x00
|
||||
|
||||
|
||||
##=================================================================================================================================
|
||||
## Subroutine to calculate the length of a null-terminated string
|
||||
## It expects the address of the first character of the
|
||||
## string, pushed onto the stack
|
||||
##=================================================================================================================================
|
||||
strlen:
|
||||
arg R1 ## Store the first argument (address of the string) into the R1 register
|
||||
mov R2, 0 ## Zero the R2 register, which will be used to store the length of the string
|
||||
_strlen_loop:
|
||||
movb ACC, *R1 ## Dereference the R1 register (pointer to the string), to get the first character of the string
|
||||
inc R1 ## Increment the R1 register (pointer to the string) so that it points to the next byte
|
||||
jeq $_streln_loop_end, 0 ## If the character ascii value is 0, we are done counting and we jump to the $_streln_loop_end label
|
||||
inc R2 ## Else, increment the R2 register, because the character is not a zero so we add 1 to the count
|
||||
jmp $_strlen_loop ## Jump to the $_strlen_loop label (beginning of the loop)
|
||||
_streln_loop_end:
|
||||
mov RV, R2 ## Copy the value of the R2 register (length of the string) to the RV register (Return Value)
|
||||
ret ## Return to the calling code
|
||||
##=================================================================================================================================
|
||||
|
||||
|
||||
|
||||
##=================================================================================================================================
|
||||
## Subroutine to calculate the fibonacci sequence
|
||||
## It expects Nth number (starting at 1) up to which
|
||||
## to calculate, pushed onto the stack
|
||||
##=================================================================================================================================
|
||||
fibonacci:
|
||||
mov R1, 0 ## R1, R2, R3 Registers will be used as variables for the calculation
|
||||
mov R2, 1 ## --
|
||||
mov R3, 1 ## --
|
||||
arg R4 ## Store the first argument (Nth number of the fibonacci sequence) into the R4 register
|
||||
mov ACC, 3 ## --
|
||||
jle $_fibonacci_loop_end, R4 ## Compare the value passed as parameter and if less or equals to 3 (ACC Register) jump to the end
|
||||
dec R4 ## Decrement the R4 register by 1, to convert from index-1 to index-0
|
||||
mov R5, 2 ## Load the numebr 2 into the R5 register, this will be used as the loop counter
|
||||
_fibonacci_loop:
|
||||
add R1, R2 ## Add R1 and R2 registers
|
||||
mov R3, ACC ## andstore the result into the R3 register
|
||||
##debug_break ## This commented debug_break can be uncommented in order to analyze every iteration of the loop in the debugger
|
||||
mov R1, R2 ## Swap the numbers around
|
||||
mov R2, R3 ## --
|
||||
mov ACC, R5 ## Load the value of the R5 register (used as the loop counter) into the ACC register
|
||||
jeq $_fibonacci_loop_end, R4 ## If the counter is equals to the R4 register (parameter passed from calling code) jump to the end of the loop
|
||||
inc R5 ## else increment the counter
|
||||
jmp $_fibonacci_loop ## and jump to the beginning of the loop
|
||||
_fibonacci_loop_end:
|
||||
mov Rv, R3 ## Load the final result (stored in the R3 register) into the RV (Return Value) register
|
||||
ret ## Return to the calling code
|
||||
##=================================================================================================================================
|
||||
|
||||
|
||||
.fixed 512, 0x00 ## This directive is used to fill (with 0x00 bytes) the binary output file from the assembler,
|
||||
## exactly to 512 bytes.
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
green='\033[0;32m'
|
||||
clear='\033[0m'
|
||||
|
||||
printf "${green}\n============================================[ Building Application ]============================================\n\n${clear}"
|
||||
\cp -r ../extra/* ./
|
||||
if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
|
||||
|
|
@ -14,7 +17,7 @@ if [ $? -eq 0 ]; then
|
|||
/bin/bash ./load_mbr
|
||||
cd ..
|
||||
printf "${green}Compiling Test Program...\n"
|
||||
./dasm dss/newTest.dss -o newTest.bin --save-disassembly disassembly/newTest.dds
|
||||
./dasm dss/newTest.dss -o newTest.bin --save-disassembly disassembly/newTest.dds --verbose
|
||||
printf "\n${green}Running Application...\n\n${clear}"
|
||||
./ddb config/testMachine.dvm --force-load newTest.bin 0x00 --verbose-load --hide-vdisplay
|
||||
# ./dvm config/testMachine.dvm --debug --force-load newTest.bin 0x00 --verbose-load
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ clear='\033[0m'
|
|||
printf "${green}Reloading BIOS...\n${clear}"
|
||||
cd ..
|
||||
cp ../extra/dss/bios.dss ./dss/bios.dss
|
||||
./dasm dss/bios.dss -o dragon/bios.bin --save-disassembly disassembly/bios.dds
|
||||
./dasm dss/bios.dss -o dragon/bios.bin --save-disassembly disassembly/bios.dds --verbose
|
||||
cp dragon/bios.bin ../extra/dragon/bios.bin
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ clear='\033[0m'
|
|||
printf "\n${green}Reloading MBR Block...\n${clear}"
|
||||
cd ..
|
||||
cp ../extra/dss/mbr.dss ./dss/mbr.dss
|
||||
./dasm dss/mbr.dss -o dragon/mbr.bin --save-disassembly disassembly/mbr.dds
|
||||
./dtools load-program dragon/disk1.dr dragon/mbr.bin 0x00000000
|
||||
./dasm dss/mbr.dss -o dragon/mbr.bin --save-disassembly disassembly/mbr.dds --verbose
|
||||
./dtools load-binary dragon/disk1.dr dragon/mbr.bin 0x00000000
|
||||
printf "\n"
|
||||
cp dragon/disk1.dr ../extra/dragon/disk1.dr
|
||||
rm dragon/mbr.bin
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
ddb config/testMachine.dvm --force-load test.bin 0x00 --verbose-load --track-step-diff --hide-vdisplay
|
||||
dasm dss/test.dss -o test.bin --save-disassembly disassembly/test.dds --verbose
|
||||
ddb config/testMachine.dvm --force-load test.bin 0x00 --verbose-load --hide-vdisplay
|
||||
|
|
@ -14,6 +14,77 @@ namespace dragon
|
|||
{
|
||||
namespace code
|
||||
{
|
||||
int32_t Assembler::Application::loadArguments(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: too few arguments.").nl();
|
||||
out.fg(ostd::ConsoleColors::Red).p("Use the --help option for more info.").reset().nl();
|
||||
return RETURN_VAL_TOO_FEW_ARGUMENTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.source_file_path = argv[1];
|
||||
if (args.source_file_path == "--help")
|
||||
{
|
||||
print_application_help();
|
||||
return RETURN_VAL_CLOSE_PROGRAM;
|
||||
}
|
||||
for (int32_t i = 2; i < argc; i++)
|
||||
{
|
||||
ostd::String edit(argv[i]);
|
||||
if (edit == "-o")
|
||||
{
|
||||
if (i == argc - 1)
|
||||
return RETURN_VAL_MISSING_PARAM;
|
||||
i++;
|
||||
args.dest_file_path = argv[i];
|
||||
}
|
||||
else if (edit == "--save-disassembly")
|
||||
{
|
||||
if (i == argc - 1)
|
||||
return RETURN_VAL_MISSING_PARAM;
|
||||
i++;
|
||||
args.disassembly_file_path = argv[i];
|
||||
args.save_disassembly = true;
|
||||
}
|
||||
else if (edit == "--help")
|
||||
{
|
||||
print_application_help();
|
||||
return RETURN_VAL_CLOSE_PROGRAM;
|
||||
}
|
||||
else if (edit == "--verbose")
|
||||
args.verbose = true;
|
||||
}
|
||||
}
|
||||
return RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void Assembler::Application::print_application_help(void)
|
||||
{
|
||||
int32_t commandLength = 46;
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Yellow).p("List of available parameters:").reset().nl();
|
||||
ostd::String tmpCommand = "--save-disassembly <destination-directory>";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Saves debug information in the destination directory.").reset().nl();
|
||||
tmpCommand = "--verbose";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Shows more information about the assembled program.").reset().nl();
|
||||
tmpCommand = "-o <destination-binary-file>";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to specify the output binary file.").reset().nl();
|
||||
tmpCommand = "--help";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Displays this help message.").reset().nl();
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Magenta).p("Usage: ./dasm <source> -o <destination> [...options...]").reset().nl();
|
||||
out.nl();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ostd::ByteStream Assembler::assembleFromFile(ostd::String fileName)
|
||||
{
|
||||
m_rawSource = "";
|
||||
|
|
@ -24,6 +95,7 @@ namespace dragon
|
|||
m_symbolTable.clear();
|
||||
m_labelTable.clear();
|
||||
m_disassembly.clear();
|
||||
m_structDefs.clear();
|
||||
m_fixedSize = 0;
|
||||
m_fixedFillValue = 0x00;
|
||||
m_loadAddress = 0x0000;
|
||||
|
|
@ -32,8 +104,12 @@ namespace dragon
|
|||
ostd::TextFileBuffer file(fileName);
|
||||
loadSource(file.rawContent());
|
||||
removeComments();
|
||||
replaceGroupDefines();
|
||||
replaceDefines();
|
||||
parseStructures();
|
||||
replaceDefines();
|
||||
parseSections();
|
||||
parseStructInstances();
|
||||
parseDataSection();
|
||||
parseCodeSection();
|
||||
replaceLabelRefs();
|
||||
|
|
@ -79,6 +155,7 @@ namespace dragon
|
|||
uint64_t da_size = 0;
|
||||
da_size += (header_string.len() + 1) * ostd::tTypeSize::BYTE;
|
||||
da_size += m_disassembly.size() * ostd::tTypeSize::DWORD; //Addresses
|
||||
da_size += m_disassembly.size() * ostd::tTypeSize::WORD; //Data Size
|
||||
da_size += m_disassembly.size() * ostd::tTypeSize::BYTE; //Null Termination
|
||||
for (auto& da : m_disassembly)
|
||||
da_size += da.code.len() * ostd::tTypeSize::BYTE; //Code Strings
|
||||
|
|
@ -90,16 +167,10 @@ namespace dragon
|
|||
{
|
||||
serializer.w_DWord(stream_addr, da.addr);
|
||||
stream_addr += ostd::tTypeSize::DWORD;
|
||||
serializer.w_Word(stream_addr, (int16_t)da.size);
|
||||
stream_addr += ostd::tTypeSize::WORD;
|
||||
serializer.w_String(stream_addr, da.code);
|
||||
stream_addr += (da.code.len() + 1) * ostd::tTypeSize::BYTE;
|
||||
// ostd::ByteStream code_stream = ostd::Utils::stringToByteStream(da.code);
|
||||
// for (int32_t i = 0; i < code_stream.size(); i++)
|
||||
// {
|
||||
// serializer.w_Byte(stream_addr, code_stream[i]);
|
||||
// stream_addr += ostd::tTypeSize::BYTE;
|
||||
// }
|
||||
// serializer.w_Byte(stream_addr, 0x00); //NULL Termination
|
||||
// stream_addr += ostd::tTypeSize::BYTE;
|
||||
}
|
||||
return serializer.saveToFile(fileName);
|
||||
}
|
||||
|
|
@ -166,7 +237,6 @@ namespace dragon
|
|||
return;
|
||||
}
|
||||
defines.push_back({ define_name, define_value });
|
||||
// std::cout << define_name << ": " << define_value << "\n";
|
||||
continue;
|
||||
}
|
||||
newLines.push_back(lineEdit);
|
||||
|
|
@ -182,6 +252,61 @@ namespace dragon
|
|||
m_lines = newLines;
|
||||
}
|
||||
|
||||
void Assembler::replaceGroupDefines(void)
|
||||
{
|
||||
std::vector<ostd::String> newLines;
|
||||
ostd::String lineEdit;
|
||||
bool in_group = false;
|
||||
ostd::String group_name = "";
|
||||
for (auto& line : m_lines)
|
||||
{
|
||||
lineEdit = line;
|
||||
lineEdit.trim();
|
||||
if (lineEdit.new_toLower().startsWith("@group "))
|
||||
{
|
||||
if (in_group)
|
||||
{
|
||||
std::cout << "Nested define groups not allowed: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
lineEdit.substr(6).trim();
|
||||
if (lineEdit == "")
|
||||
{
|
||||
std::cout << "Group name cannot be empty: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
group_name = lineEdit;
|
||||
in_group = true;
|
||||
continue;
|
||||
}
|
||||
else if (in_group && lineEdit.new_toLower() == "@end")
|
||||
{
|
||||
if (!in_group)
|
||||
{
|
||||
std::cout << "Missing group declaration for @end directive: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
in_group = false;
|
||||
continue;
|
||||
}
|
||||
if (!in_group)
|
||||
{
|
||||
newLines.push_back(lineEdit);
|
||||
continue;
|
||||
}
|
||||
if (!lineEdit.contains(" "))
|
||||
{
|
||||
std::cout << "Invalid definition inside group: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
ostd::String newLine = "@define ";
|
||||
newLine.add(group_name).add(".").add(lineEdit);
|
||||
newLines.push_back(newLine);
|
||||
}
|
||||
m_lines.clear();
|
||||
m_lines = newLines;
|
||||
}
|
||||
|
||||
void Assembler::parseSections(void)
|
||||
{
|
||||
constexpr uint8_t DATA_SECTION = 0x01;
|
||||
|
|
@ -274,6 +399,258 @@ namespace dragon
|
|||
}
|
||||
}
|
||||
|
||||
void Assembler::parseStructInstances(void)
|
||||
{
|
||||
std::vector<ostd::String> newLines;
|
||||
ostd::String lineEdit;
|
||||
bool in_group = false;
|
||||
ostd::String group_name = "";
|
||||
for (auto& line : m_rawDataSection)
|
||||
{
|
||||
lineEdit = line;
|
||||
lineEdit.trim();
|
||||
if (!lineEdit.startsWith("$") || lineEdit.indexOf(" ") < 2)
|
||||
{
|
||||
std::cout << "Invalid data entry: " << lineEdit << "\n";
|
||||
return;
|
||||
}
|
||||
ostd::String symbolName = lineEdit.new_substr(0, lineEdit.indexOf(" "));
|
||||
symbolName.trim();
|
||||
lineEdit.substr(lineEdit.indexOf(" ") + 1);
|
||||
lineEdit.trim();
|
||||
ostd::String initialization_data = "";
|
||||
bool has_init_data = false;
|
||||
if (lineEdit.startsWith("<") && lineEdit.contains("="))
|
||||
{
|
||||
initialization_data = lineEdit.new_substr(lineEdit.indexOf("=") + 1).trim();
|
||||
if (initialization_data.startsWith("(") && initialization_data.endsWith(")"))
|
||||
{
|
||||
initialization_data.substr(1, initialization_data.len() - 1).trim();
|
||||
has_init_data = initialization_data != "";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Invalid initialization data: " << lineEdit << "\n";
|
||||
return;
|
||||
}
|
||||
lineEdit.substr(0, lineEdit.indexOf("=")).trim();
|
||||
}
|
||||
if (lineEdit.startsWith("<") && lineEdit.endsWith(">") && lineEdit.len() > 2)
|
||||
{
|
||||
lineEdit = lineEdit.substr(1, lineEdit.len() - 1);
|
||||
std::vector<uint8_t> init_data;
|
||||
if (has_init_data)
|
||||
{
|
||||
auto tokens = initialization_data.tokenize(",");
|
||||
while (tokens.hasNext())
|
||||
{
|
||||
ostd::String tok = tokens.next();
|
||||
if (!tok.isNumeric())
|
||||
{
|
||||
std::cout << "Invalid initialization data: " << lineEdit << "\n";
|
||||
return;
|
||||
}
|
||||
init_data.push_back((uint8_t)tok.toInt());
|
||||
}
|
||||
}
|
||||
tStructDefinition struct_def;
|
||||
bool found = false;
|
||||
for (auto& _struct : m_structDefs)
|
||||
{
|
||||
if (_struct.name == lineEdit)
|
||||
{
|
||||
struct_def = _struct;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
std::cout << "Unknown Structure name: " << lineEdit << "\n";
|
||||
return;
|
||||
}
|
||||
if (has_init_data && struct_def.size != init_data.size())
|
||||
{
|
||||
std::cout << "Structure size must match initialization data size: " << lineEdit << "\n";
|
||||
return;
|
||||
}
|
||||
int32_t data_index = 0;
|
||||
for (auto& member : struct_def.members)
|
||||
{
|
||||
ostd::String newLine = symbolName;
|
||||
newLine.add(".").add(member.name).add(" ");
|
||||
for (int32_t i = 0; i < member.data.size(); i++, data_index++)
|
||||
{
|
||||
if (has_init_data)
|
||||
newLine.add(ostd::Utils::getHexStr(init_data[data_index], true, 2));
|
||||
else
|
||||
newLine.add(ostd::Utils::getHexStr(member.data[i], true, 2));
|
||||
newLine.add(",");
|
||||
}
|
||||
newLine.substr(0, newLine.len() - 1);
|
||||
newLines.push_back(newLine);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
newLines.push_back(line);
|
||||
}
|
||||
m_rawDataSection.clear();
|
||||
m_rawDataSection = newLines;
|
||||
}
|
||||
|
||||
void Assembler::parseStructures(void)
|
||||
{
|
||||
std::vector<ostd::String> newLines;
|
||||
ostd::String lineEdit;
|
||||
bool in_struct = false;
|
||||
ostd::String struct_name = "";
|
||||
tStructDefinition struct_def;
|
||||
int32_t member_index = 0;
|
||||
for (auto& line : m_lines)
|
||||
{
|
||||
lineEdit = line;
|
||||
lineEdit.trim();
|
||||
if (lineEdit.new_toLower().startsWith("@struct "))
|
||||
{
|
||||
if (in_struct)
|
||||
{
|
||||
std::cout << "Nested structs not allowed: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
lineEdit.substr(7).trim();
|
||||
if (lineEdit == "")
|
||||
{
|
||||
std::cout << "Struct name cannot be empty: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
struct_name = lineEdit;
|
||||
struct_def.members.clear();
|
||||
struct_def.name = struct_name;
|
||||
member_index = 0;
|
||||
in_struct = true;
|
||||
continue;
|
||||
}
|
||||
else if (in_struct && lineEdit.new_toLower() == "@end")
|
||||
{
|
||||
if (!in_struct)
|
||||
{
|
||||
std::cout << "Missing struct declaration for @end directive: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
struct_def.size = 0;
|
||||
for (auto& data : struct_def.members)
|
||||
struct_def.size += data.data.size();
|
||||
std::sort(struct_def.members.begin(), struct_def.members.end());
|
||||
m_structDefs.push_back(struct_def);
|
||||
ostd::String size_def = "@define ";
|
||||
size_def.add(struct_def.name).add(".").add("SIZE").add(" ");
|
||||
size_def.add(ostd::Utils::getHexStr(struct_def.size, true, 2));
|
||||
newLines.push_back(size_def);
|
||||
in_struct = false;
|
||||
continue;
|
||||
}
|
||||
if (!in_struct)
|
||||
{
|
||||
newLines.push_back(lineEdit);
|
||||
continue;
|
||||
}
|
||||
if (!lineEdit.contains(":"))
|
||||
{
|
||||
std::cout << "Invalid definition inside struct. Size specification missing: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
ostd::String member_name = lineEdit.new_substr(0, lineEdit.indexOf(":")).trim();
|
||||
ostd::String member_data = "";
|
||||
lineEdit.substr(lineEdit.indexOf(":") + 1).trim();
|
||||
if (member_name.contains(" "))
|
||||
{
|
||||
std::cout << "Invalid definition inside struct. Member name cannot contain spaces: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
if (lineEdit.contains(">"))
|
||||
{
|
||||
member_data = lineEdit.new_substr(lineEdit.indexOf(">") + 1).trim();
|
||||
lineEdit.substr(0, lineEdit.indexOf(">")).trim();
|
||||
}
|
||||
if (!lineEdit.isNumeric())
|
||||
{
|
||||
std::cout << "Invalid definition inside struct. Member size must be numeric: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
int32_t bytes = lineEdit.toInt();
|
||||
if (bytes < 1)
|
||||
{
|
||||
std::cout << "Invalid definition inside struct. Member must be at least 1 Byte: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
tStructMember member;
|
||||
member.position = member_index++;
|
||||
member.name = member_name;
|
||||
if (member_data == "")
|
||||
{
|
||||
for (int32_t i = 0; i < bytes; i++)
|
||||
member.data.push_back(0x00);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tokens = member_data.tokenize(",");
|
||||
if (tokens.count() == 1)
|
||||
{
|
||||
ostd::String tok = tokens.next();
|
||||
if (tok.isNumeric())
|
||||
{
|
||||
uint8_t data = (uint8_t)tok.toInt();
|
||||
for (int32_t i = 0; i < bytes; i++)
|
||||
member.data.push_back(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Invalid definition inside struct. Member data must be numeric: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tokens.count() != bytes)
|
||||
{
|
||||
std::cout << "Invalid definition inside struct. Member data count and size mismatch: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
while (tokens.hasNext())
|
||||
{
|
||||
ostd::String tok = tokens.next();
|
||||
if (tok.isNumeric())
|
||||
{
|
||||
uint8_t data = (uint8_t)tok.toInt();
|
||||
member.data.push_back(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Invalid definition inside struct. Member data must be numeric: " << line << "\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct_def.members.push_back(member);
|
||||
}
|
||||
m_lines.clear();
|
||||
m_lines = newLines;
|
||||
|
||||
// for (auto& str : m_structDefs)
|
||||
// {
|
||||
// std::cout << str.name << "\n";
|
||||
// for(auto& d : str.memberData)
|
||||
// {
|
||||
// std::cout << " " << d.first << " ";
|
||||
// for (auto& b : d.second)
|
||||
// std::cout << ostd::Utils::getHexStr(b) << " ";
|
||||
// }
|
||||
// std::cout << "\n";
|
||||
// }
|
||||
// std::cin.get();
|
||||
}
|
||||
|
||||
void Assembler::parseDataSection(void)
|
||||
{
|
||||
for (auto& line : m_rawDataSection)
|
||||
|
|
@ -287,7 +664,7 @@ namespace dragon
|
|||
}
|
||||
ostd::String symbolName = lineEdit.new_substr(0, lineEdit.indexOf(" "));
|
||||
symbolName.trim();
|
||||
lineEdit = lineEdit.substr(lineEdit.indexOf(" ") + 1);
|
||||
lineEdit.substr(lineEdit.indexOf(" ") + 1);
|
||||
lineEdit.trim();
|
||||
if (lineEdit.isNumeric())
|
||||
{
|
||||
|
|
@ -314,7 +691,7 @@ namespace dragon
|
|||
symbol.bytes.push_back((uint8_t)c);
|
||||
symbol.bytes.push_back((uint8_t)0); //NULL Termination
|
||||
symbol.address = m_currentDataAddr;
|
||||
m_currentDataAddr += lineEdit.len();
|
||||
m_currentDataAddr += symbol.bytes.size();
|
||||
m_symbolTable[symbolName] = symbol;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -500,6 +877,19 @@ namespace dragon
|
|||
m_code.push_back((uint8_t)word);
|
||||
return;
|
||||
}
|
||||
else if (instEdit == "arg")
|
||||
{
|
||||
eOperandType opType = parseOperand(opEdit, word);
|
||||
if (opType != eOperandType::Register)
|
||||
{
|
||||
std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n";
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
m_code.push_back(data::OpCodes::ArgReg);
|
||||
m_code.push_back((uint8_t)word);
|
||||
return;
|
||||
}
|
||||
else if (instEdit == "push")
|
||||
{
|
||||
eOperandType opType = parseOperand(opEdit, word);
|
||||
|
|
@ -998,7 +1388,7 @@ namespace dragon
|
|||
m_disassembly.push_back({ 0xFFFFFF00, "{ DATA }" });
|
||||
for (auto& d : m_symbolTable)
|
||||
{
|
||||
m_disassembly.push_back({ d.second.address, d.first });
|
||||
m_disassembly.push_back({ d.second.address, d.first, (uint16_t)d.second.bytes.size() });
|
||||
}
|
||||
m_disassembly.push_back({ 0xFFFFFF01, "{ LABELS }" });
|
||||
for (auto& l : m_labelTable)
|
||||
|
|
@ -1121,32 +1511,55 @@ namespace dragon
|
|||
return data::Registers::Last;
|
||||
}
|
||||
|
||||
void Assembler::tempPrint(void)
|
||||
void Assembler::printProgramInfo(void)
|
||||
{
|
||||
int32_t symbol_len = 30;
|
||||
out.nl();
|
||||
|
||||
if (m_symbolTable.size() > 0)
|
||||
out.fg(ostd::ConsoleColors::Yellow).p("Symbols:").nl();
|
||||
for (auto& symbol : m_symbolTable)
|
||||
{
|
||||
std::cout << symbol.first << "\n";
|
||||
std::cout << ostd::Utils::getHexStr(symbol.second.address, true, 2) << "\n";
|
||||
out.fg(ostd::ConsoleColors::Red).p(ostd::Utils::getHexStr(symbol.second.address, true, 2));
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" ").p(symbol.first);
|
||||
out.fg(ostd::ConsoleColors::Blue).nl().p(" ");
|
||||
for (auto& b : symbol.second.bytes)
|
||||
std::cout << ostd::Utils::getHexStr(b, true, 1) << " ";
|
||||
std::cout << "\n\n";
|
||||
out.p(ostd::Utils::getHexStr(b, false, 1)).p(".");
|
||||
out.nl();
|
||||
}
|
||||
if (m_symbolTable.size() > 0)
|
||||
out.nl();
|
||||
|
||||
std::cout << "Fixed Size: " << (int)m_fixedSize << "\n";
|
||||
std::cout << "Fixed Fill: " << ostd::Utils::getHexStr(m_fixedFillValue, true, 1) << "\n";
|
||||
std::cout << "Load Address: " << ostd::Utils::getHexStr(m_loadAddress, true, 2) << "\n";
|
||||
std::cout << "Data Size: " << (int)m_dataSize << "\n";
|
||||
std::cout << "Code Start Address: " << ostd::Utils::getHexStr(m_dataSize + m_loadAddress + 3, true, 2) << "\n";
|
||||
std::cout << "Program Size: " << (int)m_programSize << "\n";
|
||||
|
||||
if (m_labelTable.size() > 0)
|
||||
out.fg(ostd::ConsoleColors::Yellow).p("Labels:").nl();
|
||||
for (auto& label : m_labelTable)
|
||||
{
|
||||
std::cout << label.first << " " << ostd::Utils::getHexStr(label.second.address, true, 2) << "\n";
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(label.first.new_fixedLength(symbol_len));
|
||||
out.fg(ostd::ConsoleColors::Red).p(ostd::Utils::getHexStr(label.second.address, true, 2)).nl();
|
||||
}
|
||||
if (m_labelTable.size() > 0)
|
||||
out.nl();
|
||||
|
||||
ostd::ConsoleOutputHandler out;
|
||||
ostd::Utils::printByteStream(m_code, 0x0000, 16, 8, out);
|
||||
std::cout << "\n\n\n\n";
|
||||
if (m_structDefs.size() > 0)
|
||||
out.fg(ostd::ConsoleColors::Yellow).p("Structures:").nl();
|
||||
for (auto& str : m_structDefs)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(str.name.new_fixedLength(symbol_len));
|
||||
out.fg(ostd::ConsoleColors::Red).p(str.size).p(" bytes").nl();
|
||||
}
|
||||
if (m_structDefs.size() > 0)
|
||||
out.nl();
|
||||
|
||||
|
||||
out.fg(ostd::ConsoleColors::Yellow).p("Program data:").nl();
|
||||
out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Fixed Size: ").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p((int)m_fixedSize).p(" bytes").nl();
|
||||
out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Program Size:").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p((int)m_programSize).p(" bytes").nl();
|
||||
out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Data Size: ").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p((int)m_dataSize).p(" bytes").nl();
|
||||
out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Fixed Fill: ").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p(ostd::Utils::getHexStr(m_fixedFillValue, true, 1)).nl();
|
||||
out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Load Address:").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p(ostd::Utils::getHexStr(m_loadAddress, true, 2)).nl();
|
||||
out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Entry Point: ").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p(ostd::Utils::getHexStr(m_dataSize + m_loadAddress + 3, true, 2)).nl();
|
||||
|
||||
out.nl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <ostd/Utils.hpp>
|
||||
#include <ostd/IOHandlers.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace dragon
|
||||
|
|
@ -13,9 +14,11 @@ namespace dragon
|
|||
{
|
||||
class Assembler
|
||||
{
|
||||
public: struct tDisassemblyLine {
|
||||
public: struct tDisassemblyLine
|
||||
{
|
||||
uint32_t addr = 0;
|
||||
ostd::String code = "";
|
||||
uint16_t size = 1;
|
||||
inline bool operator<(const tDisassemblyLine& second) const { return addr < second.addr; }
|
||||
inline bool operator>(const tDisassemblyLine& second) const { return addr > second.addr; }
|
||||
};
|
||||
|
|
@ -29,7 +32,22 @@ namespace dragon
|
|||
std::vector<uint16_t> references;
|
||||
uint16_t address { 0 };
|
||||
};
|
||||
public: enum class eOperandType {
|
||||
public: struct tStructMember
|
||||
{
|
||||
ostd::String name;
|
||||
std::vector<uint8_t> data;
|
||||
int32_t position;
|
||||
inline bool operator<(const tStructMember& second) const { return position < second.position; }
|
||||
inline bool operator>(const tStructMember& second) const { return position > second.position; }
|
||||
};
|
||||
public: struct tStructDefinition
|
||||
{
|
||||
ostd::String name;
|
||||
std::vector<tStructMember> members;
|
||||
int32_t size;
|
||||
};
|
||||
public: enum class eOperandType
|
||||
{
|
||||
Register = 0,
|
||||
Immediate,
|
||||
DerefMemory,
|
||||
|
|
@ -39,6 +57,30 @@ namespace dragon
|
|||
Error
|
||||
};
|
||||
|
||||
public: class Application
|
||||
{
|
||||
public: struct tCommandLineArgs
|
||||
{
|
||||
inline tCommandLineArgs(void) { }
|
||||
ostd::String source_file_path { "" };
|
||||
ostd::String dest_file_path = { "" };
|
||||
bool save_disassembly = { false };
|
||||
bool verbose = { false };
|
||||
ostd::String disassembly_file_path = { "" };
|
||||
};
|
||||
|
||||
public:
|
||||
static int32_t loadArguments(int argc, char** argv);
|
||||
static void print_application_help(void);
|
||||
|
||||
public:
|
||||
inline static tCommandLineArgs args;
|
||||
inline static const int32_t RETURN_VAL_EXIT_SUCCESS = 0;
|
||||
inline static const int32_t RETURN_VAL_CLOSE_PROGRAM = 512;
|
||||
inline static const int32_t RETURN_VAL_TOO_FEW_ARGUMENTS = 1;
|
||||
inline static const int32_t RETURN_VAL_MISSING_PARAM = 2;
|
||||
};
|
||||
|
||||
public:
|
||||
static ostd::ByteStream assembleFromFile(ostd::String fileName);
|
||||
static void loadSource(ostd::String source);
|
||||
|
|
@ -46,12 +88,15 @@ namespace dragon
|
|||
static ostd::ByteStream assembleToVirtualDisk(ostd::String fileName, hw::VirtualHardDrive& vhdd, uint32_t address);
|
||||
static bool saveDisassemblyToFile(ostd::String fileName);
|
||||
|
||||
static void tempPrint(void);
|
||||
static void printProgramInfo(void);
|
||||
|
||||
private:
|
||||
static void removeComments(void);
|
||||
static void replaceDefines(void);
|
||||
static void replaceGroupDefines(void);
|
||||
static void parseSections(void);
|
||||
static void parseStructInstances(void);
|
||||
static void parseStructures(void);
|
||||
static void parseDataSection(void);
|
||||
static void parseCodeSection(void);
|
||||
static void parseDebugOperands(ostd::String line);
|
||||
|
|
@ -80,8 +125,11 @@ namespace dragon
|
|||
inline static uint16_t m_currentDataAddr { 0x0000 };
|
||||
inline static uint16_t m_dataSize { 0x0000 };
|
||||
inline static uint16_t m_programSize { 0x0000 };
|
||||
inline static std::vector<tStructDefinition> m_structDefs;
|
||||
|
||||
inline static std::vector<tDisassemblyLine> m_disassembly;
|
||||
|
||||
inline static ostd::ConsoleOutputHandler out;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +1,17 @@
|
|||
#include "Assembler.hpp"
|
||||
#include <ostd/Utils.hpp>
|
||||
#include <ostd/IOHandlers.hpp>
|
||||
|
||||
ostd::ConsoleOutputHandler out;
|
||||
|
||||
|
||||
struct tCommandLineArgs
|
||||
{
|
||||
ostd::String source_file_path = "";
|
||||
ostd::String dest_file_path = "";
|
||||
bool save_disassembly = false;
|
||||
bool verbose = false;
|
||||
ostd::String disassembly_file_path = "";
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
tCommandLineArgs args;
|
||||
if (argc < 4)
|
||||
{
|
||||
out.fg("red").p("Error: too few arguments.").nl();
|
||||
out.fg("red").p(" Usage: ./dasm <source> -o <destination> [...options...]").reset().nl();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.source_file_path = argv[1];
|
||||
for (int32_t i = 2; i < argc; i++)
|
||||
{
|
||||
ostd::String edit(argv[i]);
|
||||
if (edit == "-o")
|
||||
{
|
||||
if (i == argc - 1)
|
||||
break; //TODO: Warning
|
||||
i++;
|
||||
args.dest_file_path = argv[i];
|
||||
}
|
||||
else if (edit == "--save-disassembly")
|
||||
{
|
||||
if (i == argc - 1)
|
||||
break; //TODO: Warning
|
||||
i++;
|
||||
args.disassembly_file_path = argv[i];
|
||||
args.save_disassembly = true;
|
||||
}
|
||||
else if (edit == "--verbose")
|
||||
args.verbose = true;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t rValue = dragon::code::Assembler::Application::loadArguments(argc, argv);
|
||||
if (rValue == dragon::code::Assembler::Application::RETURN_VAL_CLOSE_PROGRAM)
|
||||
return dragon::code::Assembler::Application::RETURN_VAL_EXIT_SUCCESS;
|
||||
if (rValue != dragon::code::Assembler::Application::RETURN_VAL_EXIT_SUCCESS)
|
||||
return rValue;
|
||||
auto& args = dragon::code::Assembler::Application::args;
|
||||
dragon::code::Assembler::assembleToFile(args.source_file_path, args.dest_file_path);
|
||||
if (args.verbose)
|
||||
dragon::code::Assembler::tempPrint();
|
||||
|
||||
dragon::code::Assembler::printProgramInfo();
|
||||
if (args.save_disassembly)
|
||||
dragon::code::Assembler::saveDisassemblyToFile(args.disassembly_file_path);
|
||||
|
||||
return 0;
|
||||
return dragon::code::Assembler::Application::RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -6,6 +6,24 @@
|
|||
|
||||
namespace dragon
|
||||
{
|
||||
//Close Event Listener
|
||||
Debugger::tCloseEventListener Debugger::closeEventListener;
|
||||
|
||||
void Debugger::tCloseEventListener::init(void)
|
||||
{
|
||||
validate();
|
||||
enableSignals();
|
||||
connectSignal(dragon::Window::Signal_OnWindowClosed);
|
||||
}
|
||||
|
||||
void Debugger::tCloseEventListener::handleSignal(ostd::tSignal& signal)
|
||||
{
|
||||
m_mainWindowClosed = signal.ID == dragon::Window::Signal_OnWindowClosed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//Debugger::Utils
|
||||
DisassemblyList Debugger::Utils::findCodeRegion(const DisassemblyList& code, uint16_t address, uint16_t codeRegionMargin)
|
||||
{
|
||||
|
|
@ -32,22 +50,30 @@ namespace dragon
|
|||
return codeRegion;
|
||||
}
|
||||
|
||||
ostd::String Debugger::Utils::findSymbol(const DisassemblyList& labels, uint16_t address)
|
||||
ostd::String Debugger::Utils::findSymbol(const DisassemblyList& list, uint16_t address, uint16_t* outSize)
|
||||
{
|
||||
for (auto& label : labels)
|
||||
for (auto& line : list)
|
||||
{
|
||||
if (label.addr == address)
|
||||
return label.code;
|
||||
if (line.addr == address)
|
||||
{
|
||||
if (outSize != nullptr)
|
||||
*outSize = line.size;
|
||||
return line.code;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
uint16_t Debugger::Utils::findSymbol(const DisassemblyList& labels, const ostd::String& symbol)
|
||||
uint16_t Debugger::Utils::findSymbol(const DisassemblyList& list, const ostd::String& symbol, uint16_t* outSize)
|
||||
{
|
||||
for (auto& label : labels)
|
||||
for (auto& line : list)
|
||||
{
|
||||
if (label.code == symbol)
|
||||
return label.addr;
|
||||
if (line.code == symbol)
|
||||
{
|
||||
if (outSize != nullptr)
|
||||
*outSize = line.size;
|
||||
return line.addr;
|
||||
}
|
||||
}
|
||||
return 0x0000;
|
||||
}
|
||||
|
|
@ -67,6 +93,39 @@ namespace dragon
|
|||
out.p("\b");
|
||||
}
|
||||
|
||||
bool Debugger::Utils::isEscapeKeyPressed(bool blocking)
|
||||
{
|
||||
ostd::KeyboardController kbc;
|
||||
kbc.disableCommandBuffer();
|
||||
kbc.disableOutput();
|
||||
if (blocking)
|
||||
{
|
||||
ostd::eKeys key = ostd::eKeys::NoKeyPressed;
|
||||
while ((key = kbc.waitForKeyPress()) != ostd::eKeys::Escape)
|
||||
{
|
||||
ostd::Utils::sleep(120);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return kbc.getPressedKey() == ostd::eKeys::Escape;
|
||||
}
|
||||
|
||||
ostd::ConsoleOutputHandler& Debugger::Utils::printFullLine(char c, const ostd::ConsoleColors::tConsoleColor& foreground)
|
||||
{
|
||||
int32_t cw = ostd::Utils::getConsoleWidth();
|
||||
ostd::String str = ostd::Utils::duplicateChar(c, cw);
|
||||
out.fg(foreground).p(str).reset().nl();
|
||||
return out;
|
||||
}
|
||||
|
||||
ostd::ConsoleOutputHandler& Debugger::Utils::printFullLine(char c, const ostd::ConsoleColors::tConsoleColor& foreground, const ostd::ConsoleColors::tConsoleColor& background)
|
||||
{
|
||||
int32_t cw = ostd::Utils::getConsoleWidth();
|
||||
ostd::String str = ostd::Utils::duplicateChar(c, cw);
|
||||
out.bg(background).fg(foreground).p(str).reset().nl();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -131,7 +190,7 @@ namespace dragon
|
|||
|
||||
void Debugger::Display::printPrompt(void)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" #/> ").fg(ostd::ConsoleColors::White);
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" (ddb) #/> ").fg(ostd::ConsoleColors::White);
|
||||
}
|
||||
|
||||
void Debugger::Display::printStep(void)
|
||||
|
|
@ -166,9 +225,7 @@ namespace dragon
|
|||
colorCodeInstructions(_da.code, currentLine, debugger.labels);
|
||||
out.reset();
|
||||
}
|
||||
int32_t cw = ostd::Utils::getConsoleWidth();
|
||||
ostd::String str = ostd::Utils::duplicateChar('#', cw);
|
||||
out.bg(ostd::ConsoleColors::Yellow).fg(ostd::ConsoleColors::Black).p(str.cpp_str()).reset().nl();
|
||||
Utils::printFullLine('#', ostd::ConsoleColors::Black, ostd::ConsoleColors::Yellow);
|
||||
}
|
||||
|
||||
void Debugger::Display::printDiff(void)
|
||||
|
|
@ -176,7 +233,7 @@ namespace dragon
|
|||
out.clear();
|
||||
|
||||
ostd::String str;
|
||||
str.add("|===============|================PREV================|================CURR================|=====|====REG====|====REG====|");
|
||||
str.add("|===============|================PREV================|================CURR================|=====|===PREV====|===CURR====|");
|
||||
str.add("\n");
|
||||
str.add("| InstAddr: |*%PREV_INST_ADDR%*******************|*%CURR_INST_ADDR%*******************| R1 |*%PREV_R1%*|*%CURR_R1%*|");
|
||||
str.add("\n");
|
||||
|
|
@ -202,19 +259,19 @@ namespace dragon
|
|||
str.add("\n");
|
||||
str.add("|---------------|------------------------------------|------------------------------------|-----|-----------|-----------|");
|
||||
str.add("\n");
|
||||
str.add("| SubRoutine: |*%PREV_SUB_ROUTINE%*****************|**%CURR_SUB_ROUTINE%****************| R6 |*%PREV_R7%*|*%CURR_R7%*|");
|
||||
str.add("| SubRoutine: |*%PREV_SUB_ROUTINE%*****************|**%CURR_SUB_ROUTINE%****************| R7 |*%PREV_R7%*|*%CURR_R7%*|");
|
||||
str.add("\n");
|
||||
str.add("|---------------|------------------------------------|------------------------------------|-----|-----------|-----------|");
|
||||
str.add("\n");
|
||||
str.add("| IP: |*%PREV_IP%**************************|**%CURR_IP%*************************| R7 |*%PREV_R8%*|*%CURR_R8%*|");
|
||||
str.add("| IP: |*%PREV_IP%**************************|**%CURR_IP%*************************| R8 |*%PREV_R8%*|*%CURR_R8%*|");
|
||||
str.add("\n");
|
||||
str.add("|---------------|------------------------------------|------------------------------------|-----|-----------|-----------|");
|
||||
str.add("\n");
|
||||
str.add("| SP: |*%PREV_SP%**************************|**%CURR_SP%*************************| R8 |*%PREV_R9%*|*%CURR_R9%*|");
|
||||
str.add("| SP: |*%PREV_SP%**************************|**%CURR_SP%*************************| R9 |*%PREV_R9%*|*%CURR_R9%*|");
|
||||
str.add("\n");
|
||||
str.add("|---------------|------------------------------------|------------------------------------|-----|-----------|-----------|");
|
||||
str.add("\n");
|
||||
str.add("| FP: |*%PREV_FP%**************************|**%CURR_FP%*************************| R9 |*%PREV_R10%|*%CURR_R10%|");
|
||||
str.add("| FP: |*%PREV_FP%**************************|**%CURR_FP%*************************| R10 |*%PREV_R10%|*%CURR_R10%|");
|
||||
str.add("\n");
|
||||
str.add("|---------------|------------------------------------|------------------------------------|=====|===========|===========|");
|
||||
str.add("\n");
|
||||
|
|
@ -741,45 +798,153 @@ namespace dragon
|
|||
rgxstr.fg("CURR", "Green");
|
||||
out.pStyled(rgxstr);
|
||||
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Enter> to continue execution...").nl().reset();
|
||||
std::cin.get();
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Escape> to go back...").nl().reset();
|
||||
Utils::isEscapeKeyPressed(true);
|
||||
}
|
||||
|
||||
void Debugger::Display::printTrackedAddresses(void)
|
||||
{
|
||||
out.clear();
|
||||
|
||||
out.fg(ostd::ConsoleColors::Yellow).p("Tracked Data: ").reset().nl();
|
||||
const int32_t symbol_len = 24;
|
||||
const int32_t size_len = 8;
|
||||
const int32_t addr_len = 10;
|
||||
const int32_t map_len = 8;
|
||||
const int32_t prev_len = 35;
|
||||
const dragon::DragonRuntime::tMachineDebugInfo& minfo = dragon::DragonRuntime::getMachineInfoDiff();
|
||||
if (minfo.trackedAddresses.size() == 0) return;
|
||||
int32_t cw = ostd::Utils::getConsoleWidth();
|
||||
ostd::String header = "|Symbol";
|
||||
header.addRightPadding(symbol_len);
|
||||
header.add("|Bytes");
|
||||
header.addRightPadding(header.len() + size_len - 6);
|
||||
header.add("|Addr");
|
||||
header.addRightPadding(header.len() + addr_len - 5);
|
||||
header.add("|Map");
|
||||
header.addRightPadding(header.len() + map_len - 4);
|
||||
header.add("|Previous");
|
||||
header.addRightPadding(header.len() + prev_len - 9);
|
||||
header.add("|Current");
|
||||
header.fixedLength(cw - 1);
|
||||
header.addChar('|');
|
||||
ostd::String border = ostd::Utils::duplicateChar('=', cw);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(border).nl();
|
||||
ostd::RegexRichString rgx(header);
|
||||
rgx.fg("\\|", "blue");
|
||||
rgx.fg("Symbol|Bytes|Addr|Map|Previous|Current", "yellow");
|
||||
out.pStyled(rgx).reset().nl();
|
||||
ostd::String h_sep = ostd::Utils::duplicateChar('=', cw);
|
||||
h_sep.put(0, '|');
|
||||
h_sep.put(symbol_len, '|');
|
||||
h_sep.put(symbol_len + size_len, '|');
|
||||
h_sep.put(symbol_len + size_len + addr_len, '|');
|
||||
h_sep.put(symbol_len + size_len + addr_len + map_len, '|');
|
||||
h_sep.put(symbol_len + size_len + addr_len + map_len + prev_len, '|');
|
||||
h_sep.put(cw - 1, '|');
|
||||
out.fg(ostd::ConsoleColors::Blue).p(h_sep).reset().nl();
|
||||
for (int32_t i = 0; i < minfo.trackedAddresses.size(); i++)
|
||||
{
|
||||
uint16_t data_size = 1;
|
||||
auto addr = minfo.trackedAddresses[i];
|
||||
ostd::String symbol = Utils::findSymbol(debugger.data, addr);
|
||||
ostd::String symbol = Utils::findSymbol(debugger.data, addr, &data_size);
|
||||
if (symbol == "")
|
||||
symbol = Utils::findSymbol(debugger.labels, addr);
|
||||
symbol.fixedLength(30);
|
||||
out.p(symbol);
|
||||
out.p(ostd::Utils::getHexStr(addr, true, 2)).p(" ");
|
||||
out.p(ostd::Utils::getHexStr(minfo.previousInstructionTrackedValues[i], true, 1)).p(" ");
|
||||
out.p(ostd::Utils::getHexStr(minfo.currentInstructionTrackedValues[i], true, 1)).p(" ");
|
||||
out.nl();
|
||||
}
|
||||
symbol = Utils::findSymbol(debugger.labels, addr, &data_size);
|
||||
bool no_symbol = false;
|
||||
if (symbol == "")
|
||||
{
|
||||
symbol = "<no-symbol>";
|
||||
no_symbol = true;
|
||||
}
|
||||
symbol.fixedLength(symbol_len - 1);
|
||||
if (no_symbol)
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::Gray).p(symbol).reset();
|
||||
else
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::Magenta).p(symbol).reset();
|
||||
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Enter> to continue execution...").nl().reset();
|
||||
std::cin.get();
|
||||
ostd::String tmp = "";
|
||||
tmp.add(data_size);
|
||||
tmp.fixedLength(size_len - 1);
|
||||
if (no_symbol)
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::Cyan).p(tmp).reset();
|
||||
else
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::BrightCyan).p(tmp).reset();
|
||||
|
||||
tmp = "";
|
||||
tmp.add(ostd::Utils::getHexStr(addr, true, 2));
|
||||
tmp.fixedLength(addr_len - 1);
|
||||
if (no_symbol)
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::Gray).p(tmp).reset();
|
||||
else
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::BrightGray).p(tmp).reset();
|
||||
|
||||
tmp = "";
|
||||
if (addr >= (uint16_t)DragonRuntime::cpu.readRegister(data::Registers::SP))
|
||||
tmp.add("STACK");
|
||||
else
|
||||
tmp.add(DragonRuntime::memMap.getMemoryRegionName(addr));
|
||||
tmp.fixedLength(map_len - 1);
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::BrightYellow).p(tmp).reset();
|
||||
|
||||
tmp = "";
|
||||
tmp.add(ostd::Utils::getHexStr(minfo.previousInstructionTrackedValues[i], false, 1));
|
||||
for (int32_t j = 1; j < data_size; j++)
|
||||
tmp.add(".").add(ostd::Utils::getHexStr(minfo.previousInstructionTrackedValues[i + j], false, 1));
|
||||
tmp.fixedLength(prev_len - 1);
|
||||
if (no_symbol)
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::Red).p(tmp).reset();
|
||||
else
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::BrightRed).p(tmp).reset();
|
||||
|
||||
tmp = "";
|
||||
tmp.add(ostd::Utils::getHexStr(minfo.currentInstructionTrackedValues[i], false, 1));
|
||||
uint32_t tmp_i = i;
|
||||
for (int32_t j = 1; j < data_size; j++, i++)
|
||||
tmp.add(".").add(ostd::Utils::getHexStr(minfo.currentInstructionTrackedValues[i + 1], false, 1));
|
||||
tmp.fixedLength(prev_len - 1);
|
||||
bool data_different = false;
|
||||
for (int32_t j = 0; j < data_size; j++)
|
||||
{
|
||||
if (minfo.currentInstructionTrackedValues[tmp_i + j] != minfo.previousInstructionTrackedValues[tmp_i + j])
|
||||
{
|
||||
data_different = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (no_symbol)
|
||||
{
|
||||
if (data_different)
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::BrightGray).p(tmp).reset();
|
||||
else
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::Green).p(tmp).reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data_different)
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::White).p(tmp).reset();
|
||||
else
|
||||
out.fg(ostd::ConsoleColors::Blue).p("|").fg(ostd::ConsoleColors::BrightGreen).p(tmp).reset();
|
||||
}
|
||||
tmp = "|";
|
||||
tmp.addLeftPadding(cw - symbol_len - size_len - addr_len - map_len - prev_len - prev_len);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmp).reset();
|
||||
}
|
||||
out.nl();
|
||||
out.fg(ostd::ConsoleColors::Blue).p(border).reset().nl();
|
||||
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Escape> to go back...").nl().reset();
|
||||
Utils::isEscapeKeyPressed(true);
|
||||
}
|
||||
|
||||
void Debugger::Display::printStack(void)
|
||||
void Debugger::Display::printStack(uint16_t nrows)
|
||||
{
|
||||
if (nrows == 0) nrows = 8;
|
||||
uint16_t ncols = 16;
|
||||
uint16_t startAddr = (0xFFFF - (ncols * nrows) + 1);
|
||||
out.clear();
|
||||
|
||||
const dragon::DragonRuntime::tMachineDebugInfo& minfo = dragon::DragonRuntime::getMachineInfoDiff();
|
||||
uint16_t stack_ptr = DragonRuntime::cpu.readRegister(data::Registers::SP);
|
||||
std::cout << " " << ostd::Utils::getHexStr(stack_ptr, true, 2) << " \n";
|
||||
ostd::Utils::printByteStream(*DragonRuntime::ram.getByteStream(), 0xFF80, 16, 8, out, stack_ptr, 1, "Stack");
|
||||
|
||||
out.nl();
|
||||
|
||||
out.fg(ostd::ConsoleColors::Yellow).p("Stack frames: ").reset().nl();
|
||||
Utils::printFullLine('=', ostd::ConsoleColors::BrightBlue);
|
||||
for (auto& frame : dragon::DragonRuntime::cpu.m_debug_stackFrameStrings)
|
||||
{
|
||||
ostd::RegexRichString rgxrstr(frame);
|
||||
|
|
@ -787,73 +952,186 @@ namespace dragon
|
|||
rgxrstr.fg("(?<!\\w)(r[1-9]|r10|fl|pp|rv|fp|sp|ip|acc)(?!\\w)", "BrightGreen", true); //Registers
|
||||
rgxrstr.fg("(?<!\\w)(args|argc|StackFrame|New FP)(?!\\w)", "Magenta", true); //Other
|
||||
|
||||
out.reset().nl().fg(ostd::ConsoleColors::BrightBlue).p("=======================").nl().reset();
|
||||
out.pStyled(rgxrstr);
|
||||
out.nl();
|
||||
Utils::printFullLine('=', ostd::ConsoleColors::BrightBlue);
|
||||
}
|
||||
out.reset().nl().fg(ostd::ConsoleColors::BrightBlue).p("=======================").nl().reset();
|
||||
out.nl();
|
||||
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Enter> to continue execution...").nl().reset();
|
||||
std::cin.get();
|
||||
out.fg(ostd::ConsoleColors::Yellow).p("Stack view: ").reset().nl();
|
||||
uint16_t stack_ptr = DragonRuntime::cpu.readRegister(data::Registers::SP);
|
||||
ostd::Utils::printByteStream(*DragonRuntime::ram.getByteStream(), startAddr, ncols, nrows, out, stack_ptr, 2, "Stack");
|
||||
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Escape> to go back...").nl().reset();
|
||||
Utils::isEscapeKeyPressed(true);
|
||||
}
|
||||
|
||||
void Debugger::Display::printCallStack(void)
|
||||
{
|
||||
out.clear();
|
||||
out.fg(ostd::ConsoleColors::Yellow).p("Subroutine/Interrupt call stack: ").reset().nl();
|
||||
Utils::printFullLine('=', ostd::ConsoleColors::Yellow);
|
||||
|
||||
const dragon::DragonRuntime::tMachineDebugInfo& minfo = dragon::DragonRuntime::getMachineInfoDiff();
|
||||
|
||||
auto& callStack = minfo.callStack;
|
||||
int32_t depth = -1;
|
||||
int32_t level = -1;
|
||||
ostd::String ch_ang_u = "";
|
||||
ch_ang_u.addChar((unsigned char)218);
|
||||
ostd::String ch_ang_l = "|";
|
||||
ostd::String ch_ang_d = "";
|
||||
ch_ang_d.addChar((unsigned char)192);
|
||||
for (auto& call : callStack)
|
||||
{
|
||||
if (call.info.new_trim().toLower().startsWith("ret"))
|
||||
depth--;
|
||||
else
|
||||
depth++;
|
||||
if (depth < 0) depth = 0;
|
||||
out.p(ostd::String().addLeftPadding(depth * 4));
|
||||
out.p(call.info.new_fixedLength(10)).p(" ");
|
||||
ostd::String call_info = call.info.new_trim().toLower();
|
||||
ostd::String subroutine_addr = ostd::Utils::getHexStr(call.addr, true, 2);
|
||||
ostd::String subroutine_name = Utils::findSymbol(debugger.labels, call.addr);
|
||||
out.p(ostd::Utils::getHexStr(call.addr, true, 2));
|
||||
if (call.info.new_trim().toLower() == "call imm" && subroutine_name != "")
|
||||
out.p(" (").p(subroutine_name).p(")");
|
||||
out.nl();
|
||||
ostd::String call_str = "";
|
||||
bool dec_lvl = false;
|
||||
if (call_info == "int")
|
||||
{
|
||||
call_str = ch_ang_u + "int " + ostd::Utils::getHexStr(call.addr, true, 1);
|
||||
level++;
|
||||
}
|
||||
else if (call_info == "ret")
|
||||
{
|
||||
call_str = ch_ang_d + "ret";
|
||||
dec_lvl = true;
|
||||
}
|
||||
else if (call_info == "ret int")
|
||||
{
|
||||
call_str = ch_ang_d + "rti";
|
||||
dec_lvl = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (call_info == "call reg")
|
||||
subroutine_addr = "*" + subroutine_addr;
|
||||
if (subroutine_name != "")
|
||||
call_str = ch_ang_u + subroutine_name + " (" + subroutine_addr + ")";
|
||||
else
|
||||
call_str = ch_ang_u + subroutine_addr;
|
||||
level++;
|
||||
}
|
||||
|
||||
ostd::String line_str = "";
|
||||
for (int32_t i = 0; i < level; i++)
|
||||
line_str.add("| ");
|
||||
line_str.add(call_str);
|
||||
|
||||
ostd::RegexRichString rgx(line_str);
|
||||
rgx.fg("\\(|\\)|\\*", "Cyan"); //Operators
|
||||
rgx.fg("(?<![a-zA-Z\\_\\$\\.])int|rti(?! [a-zA-Z\\_\\$\\.])", "Blue");
|
||||
rgx.fg("(?<![a-zA-Z\\_\\$\\.])ret(?! [a-zA-Z\\_\\$\\.])", "Red");
|
||||
rgx.fg("0x[0-9A-Fa-f]+|0b[0-1]+|(?<!\\w)[0-9]+(?!\\w)", "BrightYellow"); //Number Constants
|
||||
rgx.fg(ostd::String("[\\").add(ch_ang_u).add("\\|\\").add(ch_ang_d).add("]"), "darkgray");
|
||||
rgx.fg("\\$\\w+", "Green"); //Labels
|
||||
|
||||
out.fg(ostd::ConsoleColors::BrightGray).p("|").reset();
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(ostd::Utils::getHexStr(call.inst_addr, true, 2));
|
||||
out.fg(ostd::ConsoleColors::BrightGray).p("| > ").reset();
|
||||
out.pStyled(rgx).nl().reset();
|
||||
|
||||
if (dec_lvl)
|
||||
level--;
|
||||
}
|
||||
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Enter> to continue execution...").nl().reset();
|
||||
std::cin.get();
|
||||
Utils::printFullLine('=', ostd::ConsoleColors::Yellow);
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Escape> to go back...").nl().reset();
|
||||
Utils::isEscapeKeyPressed(true);
|
||||
}
|
||||
|
||||
void Debugger::Display::printHelp(void)
|
||||
{
|
||||
out.clear();
|
||||
int32_t commandLength = 34;
|
||||
Utils::printFullLine('#', ostd::ConsoleColors::Black, ostd::ConsoleColors::Red);
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Yellow).p("List of available commands:").reset().nl();
|
||||
ostd::String tmpCommand = "(d)iff-view";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to show the state of the machine, comparing the current cycle with the last.").reset().nl();
|
||||
tmpCommand = "(q)uit";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to close the program and exit the debugger. (<Escape> key can also be used.)").reset().nl();
|
||||
tmpCommand = "(h)elp";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to show this dialog.").reset().nl();
|
||||
tmpCommand = "(t)racker";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to show manually tracked values.").reset().nl();
|
||||
tmpCommand = "(s)tack [rows=8]";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to show the stack and a description of every stack-frame saved.").reset().nl();
|
||||
tmpCommand = "(ca)ll-stack";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to show information about all subroutine/interrupt calls.").reset().nl();
|
||||
tmpCommand = "(c)ontinue";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used exit step-execution mode and resume the normal execution of the program.").reset().nl();
|
||||
tmpCommand = "(p)rint [word] <addr/symbol>";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to print values from memory. Valid [size] values are: byte/word/dword/qword.").reset().nl();
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Cyan).p("The letters in parenthesis can be used as the short version of the command.").nl();
|
||||
out.p("Square brackets represent optional parameters. If they have an '=' and a value, that is the default if not specified.").reset().nl();
|
||||
|
||||
out.nl();
|
||||
Utils::printFullLine('#', ostd::ConsoleColors::Black, ostd::ConsoleColors::Red);
|
||||
|
||||
out.nl().nl().fg(ostd::ConsoleColors::Yellow).p("Pres <Escape> to go back...").nl().reset();
|
||||
Utils::isEscapeKeyPressed(true);
|
||||
}
|
||||
|
||||
ostd::String Debugger::Display::changeScreen(void)
|
||||
{
|
||||
if (debugger.command == "diff")
|
||||
if (debugger.command == "diff-view" || debugger.command == "d")
|
||||
{
|
||||
printDiff();
|
||||
printStep();
|
||||
printPrompt();
|
||||
return getCommandInput();
|
||||
}
|
||||
else if (debugger.command == "tracker")
|
||||
else if (debugger.command == "tracker" || debugger.command == "t")
|
||||
{
|
||||
printTrackedAddresses();
|
||||
printStep();
|
||||
printPrompt();
|
||||
return getCommandInput();
|
||||
}
|
||||
else if (debugger.command == "stack")
|
||||
else if (debugger.command.startsWith("stack") || debugger.command.startsWith("s"))
|
||||
{
|
||||
printStack();
|
||||
uint16_t default_stack_rows = 8;
|
||||
ostd::String params = debugger.command.new_trim();
|
||||
if (params == "stack" || params == "s")
|
||||
printStack(default_stack_rows);
|
||||
else if (params.contains(" "))
|
||||
{
|
||||
params.substr(params.indexOf(" ") + 1).trim();
|
||||
if (!params.isNumeric()) return "";
|
||||
default_stack_rows = (uint16_t)params.toInt();
|
||||
if (default_stack_rows > 0xFFFF / 16) default_stack_rows = 8;
|
||||
printStack(default_stack_rows);
|
||||
}
|
||||
else return "";
|
||||
printStep();
|
||||
printPrompt();
|
||||
return getCommandInput();
|
||||
}
|
||||
else if (debugger.command == "call")
|
||||
else if (debugger.command == "call-stack" || debugger.command == "ca")
|
||||
{
|
||||
printCallStack();
|
||||
printStep();
|
||||
printPrompt();
|
||||
return getCommandInput();
|
||||
}
|
||||
else if (debugger.command == "help" || debugger.command == "h")
|
||||
{
|
||||
printHelp();
|
||||
printStep();
|
||||
printPrompt();
|
||||
return getCommandInput();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
@ -876,12 +1154,18 @@ namespace dragon
|
|||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
out.fg("red").p("Error, too few arguments.").reset().nl();
|
||||
return 128;
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: too few arguments.").nl();
|
||||
out.fg(ostd::ConsoleColors::Red).p("Use the --help option for more info.").reset().nl();
|
||||
return DragonRuntime::RETURN_VAL_TOO_FEW_ARGUMENTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger.args.machine_config_path = argv[1];
|
||||
if (debugger.args.machine_config_path == "--help")
|
||||
{
|
||||
print_application_help();
|
||||
return DragonRuntime::RETURN_VAL_CLOSE_DEBUGGER;
|
||||
}
|
||||
for (int32_t i = 2; i < argc; i++)
|
||||
{
|
||||
ostd::String edit(argv[i]);
|
||||
|
|
@ -891,6 +1175,8 @@ namespace dragon
|
|||
debugger.args.step_exec = true;
|
||||
else if (edit == "--track-step-diff-off")
|
||||
debugger.args.track_step_diff = false;
|
||||
else if (edit == "--auto-track-data-off")
|
||||
debugger.args.auto_track_all_data_symbols = false;
|
||||
else if (edit == "--hide-vdisplay")
|
||||
debugger.args.hide_virtual_display = true;
|
||||
else if (edit == "--auto-start")
|
||||
|
|
@ -898,19 +1184,24 @@ namespace dragon
|
|||
else if (edit == "--force-load")
|
||||
{
|
||||
if ((argc - 1) - i < 2)
|
||||
break; //TODO: Warning
|
||||
return DragonRuntime::RETURN_VAL_MISSING_PARAM;
|
||||
i++;
|
||||
debugger.args.force_load_file = argv[i];
|
||||
i++;
|
||||
edit = argv[i];
|
||||
if (!edit.isNumeric())
|
||||
continue; //TODO: Error
|
||||
return DragonRuntime::RETURN_VAL_PARAMETER_NOT_NUMERIC;
|
||||
debugger.args.force_load_mem_offset = (uint16_t)edit.toInt();
|
||||
debugger.args.force_load = true;
|
||||
}
|
||||
else if (edit == "--help")
|
||||
{
|
||||
print_application_help();
|
||||
return DragonRuntime::RETURN_VAL_CLOSE_DEBUGGER;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return DragonRuntime::RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t Debugger::initRuntime(void)
|
||||
|
|
@ -921,6 +1212,7 @@ namespace dragon
|
|||
debugger.args.hide_virtual_display,
|
||||
debugger.args.track_call_stack,
|
||||
true); //CPU Debug Mode Enabled
|
||||
closeEventListener.init();
|
||||
if (init_state != 0) return init_state; //TODO: Error
|
||||
|
||||
if (debugger.args.force_load)
|
||||
|
|
@ -931,49 +1223,348 @@ namespace dragon
|
|||
debugger.labels = dragon::DisassemblyLoader::getLabelTable();
|
||||
debugger.data = dragon::DisassemblyLoader::getDataTable();
|
||||
|
||||
return 0;
|
||||
return DragonRuntime::RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
ostd::String Debugger::getCommandInput(void)
|
||||
{
|
||||
// ostd::String cmd;
|
||||
// ostd::KeyboardController keyboard;
|
||||
|
||||
// ostd::eKeys key = ostd::eKeys::NoKeyPressed;
|
||||
// int32_t commandHistoryIndex = ZERO(commandHistory.size() - 1);
|
||||
// while (key != ostd::eKeys::Enter)
|
||||
// {
|
||||
// key = keyboard.waitForKeyPress();
|
||||
// if (key == ostd::eKeys::Up)
|
||||
// {
|
||||
// if (commandHistory.size() == 0)
|
||||
// continue;
|
||||
// Utils::clearConsoleLine();
|
||||
// Display::printPrompt();
|
||||
// out.p(commandHistory[commandHistoryIndex]);
|
||||
// commandHistoryIndex = ZERO(commandHistoryIndex - 1);
|
||||
// }
|
||||
// else if (key == ostd::eKeys::Down)
|
||||
// {
|
||||
// if (commandHistory.size() == 0)
|
||||
// continue;
|
||||
// Utils::clearConsoleLine();
|
||||
// Display::printPrompt();
|
||||
// out.p(commandHistory[commandHistoryIndex]);
|
||||
// commandHistoryIndex = CAP(commandHistoryIndex + 1, commandHistory.size() - 1);
|
||||
// }
|
||||
// else if (key == ostd::eKeys::Enter)
|
||||
// {
|
||||
// cmd = keyboard.getInputString();
|
||||
// commandHistory.push_back(cmd);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return cmd;
|
||||
|
||||
ostd::String cmd;
|
||||
std::getline(std::cin, cmd.cpp_str_ref());
|
||||
return cmd;
|
||||
ostd::KeyboardController kbc;
|
||||
ostd::eKeys key = ostd::eKeys::NoKeyPressed;
|
||||
|
||||
while ((key = kbc.getPressedKey()) != ostd::eKeys::Enter)
|
||||
{
|
||||
if (key == ostd::eKeys::Escape)
|
||||
return InputCommandQuit;
|
||||
}
|
||||
return kbc.getInputString();
|
||||
|
||||
// ostd::String cmd;
|
||||
// std::getline(std::cin, cmd.cpp_str_ref());
|
||||
// return cmd;
|
||||
}
|
||||
|
||||
int32_t Debugger::topLevelPrompt(void)
|
||||
{
|
||||
if (!data().args.auto_start_debug)
|
||||
{
|
||||
bool exit_loop = false;
|
||||
bool done_with_auto_data_track = false;
|
||||
DragonRuntime::vDisplay.hide();
|
||||
while (!exit_loop)
|
||||
{
|
||||
if (!done_with_auto_data_track)
|
||||
{
|
||||
data().command = "track ";
|
||||
for (auto& sym : debugger.data)
|
||||
data().command.add(sym.code).add(" ");
|
||||
done_with_auto_data_track = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Display::printPrompt();
|
||||
data().command = getCommandInput();
|
||||
}
|
||||
data().command.trim().toLower();
|
||||
if (data().command == "r" || data().command == "run")
|
||||
{
|
||||
output().p("Starting program...").nl();
|
||||
exit_loop = true;
|
||||
}
|
||||
else if (data().command == "q" || data().command == "quit" || data().command == InputCommandQuit)
|
||||
{
|
||||
output().nl().p("Exiting debugger...").nl();
|
||||
return DragonRuntime::RETURN_VAL_CLOSE_DEBUGGER;
|
||||
}
|
||||
else if (data().command.startsWith("t ") || data().command.startsWith("track "))
|
||||
{
|
||||
data().command.substr(data().command.indexOf(" ") + 1).trim();
|
||||
exec_watch_command();
|
||||
}
|
||||
else if (data().command == "h" || data().command == "help")
|
||||
{
|
||||
print_top_level_prompt_help();
|
||||
}
|
||||
else if (data().command == "s" || data().command == "step")
|
||||
{
|
||||
data().args.step_exec = !data().args.step_exec;
|
||||
output().p("Step execution = ").p(STR_BOOL(data().args.step_exec)).nl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!data().args.hide_virtual_display)
|
||||
DragonRuntime::vDisplay.show();
|
||||
|
||||
data().currentAddress = DragonRuntime::cpu.readRegister(data::Registers::IP);
|
||||
return DragonRuntime::RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t Debugger::executeRuntime(void)
|
||||
{
|
||||
int32_t rValue = 0;
|
||||
bool userQuit = false;
|
||||
output().clear().fg(ostd::ConsoleColors::Green).p("Program running...").nl();
|
||||
if (!data().args.step_exec)
|
||||
output().fg(ostd::ConsoleColors::Yellow).p("Press <Escape> to enter in step-execution mode...").reset().nl();
|
||||
while (!userQuit)
|
||||
{
|
||||
ostd::SignalHandler::refresh();
|
||||
if (closeEventListener.hasHappened())
|
||||
userQuit = true;
|
||||
data().command.clr();
|
||||
if (!userQuit && data().args.step_exec)
|
||||
rValue = step_execution(userQuit, true);
|
||||
else if (!userQuit)
|
||||
rValue = normal_runtime(userQuit);
|
||||
data().currentAddress = DragonRuntime::cpu.readRegister(data::Registers::IP);
|
||||
}
|
||||
output().nl().fg(ostd::ConsoleColors::Yellow).p("Execution terminated.").nl().nl().reset();
|
||||
return rValue;
|
||||
}
|
||||
|
||||
int32_t Debugger::step_execution(bool& outUserQuit, bool exec_first_step)
|
||||
{
|
||||
if (exec_first_step && !DragonRuntime::cpu.isHalted())
|
||||
DragonRuntime::runStep(data().trackedAddresses);
|
||||
Display::printStep();
|
||||
processErrors();
|
||||
if (DragonRuntime::cpu.isInDebugBreakPoint())
|
||||
output().fg(ostd::ConsoleColors::Red).p("Reached Debug Break Point.").reset().nl();
|
||||
Display::printPrompt();
|
||||
data().command = getCommandInput();
|
||||
data().command.trim().toLower();
|
||||
while (data().command != "")
|
||||
{
|
||||
if (data().command == "q" || data().command == "quit" || data().command == InputCommandQuit)
|
||||
{
|
||||
output().nl();
|
||||
outUserQuit = true;
|
||||
data().command = "";
|
||||
}
|
||||
else if (data().command == "c" || data().command == "continue")
|
||||
{
|
||||
data().args.step_exec = false;
|
||||
data().command = "";
|
||||
output().clear().fg(ostd::ConsoleColors::Green).p("Program running...").nl();
|
||||
output().fg(ostd::ConsoleColors::Yellow).p("Press <Escape> to enter in step-execution mode...").reset().nl();
|
||||
}
|
||||
else if (data().command.startsWith("p ") || data().command.startsWith("print "))
|
||||
{
|
||||
data().command.substr(data().command.indexOf(" ") + 1).trim();
|
||||
const uint8_t TYPE_BYTE = 1;
|
||||
const uint8_t TYPE_WORD = 2;
|
||||
const uint8_t TYPE_DWORD = 4;
|
||||
const uint8_t TYPE_QWORD = 8;
|
||||
uint8_t type = TYPE_WORD;
|
||||
if (data().command.contains(" "))
|
||||
{
|
||||
ostd::String size_str = data().command.new_substr(0, data().command.indexOf(" ")).trim();
|
||||
data().command.substr(data().command.indexOf(" ") + 1).trim();
|
||||
if (size_str == "byte") type = TYPE_BYTE;
|
||||
else if (size_str == "word") type = TYPE_WORD;
|
||||
else if (size_str == "dword") type = TYPE_DWORD;
|
||||
else if (size_str == "qword") type = TYPE_QWORD;
|
||||
}
|
||||
if (data().command.isNumeric())
|
||||
{
|
||||
uint16_t addr = data().command.toInt();
|
||||
uint16_t end_addr = addr;
|
||||
ostd::String tmp = "";
|
||||
tmp.add("*(").add(ostd::Utils::getHexStr(addr, true, 2));
|
||||
if (type != TYPE_BYTE)
|
||||
{
|
||||
end_addr = addr + type - 1;
|
||||
if (end_addr < addr)
|
||||
end_addr = addr;
|
||||
else
|
||||
tmp.add("-").add(ostd::Utils::getHexStr(end_addr, true, 2));
|
||||
}
|
||||
tmp.add(")");
|
||||
ostd::RegexRichString rgx(tmp);
|
||||
rgx.fg("\\(|\\)|-", "darkgray");
|
||||
rgx.fg("\\*", "red");
|
||||
rgx.fg("0x[0-9A-Fa-f]+|0b[0-1]+|(?<!\\w)[0-9]+(?!\\w)", "cyan"); //Number Constants
|
||||
output().pStyled(rgx);
|
||||
output().fg(ostd::ConsoleColors::White).p(" = ");
|
||||
output().fg(ostd::ConsoleColors::Gray).p("[");
|
||||
for (uint16_t a = addr; a <= end_addr; a++)
|
||||
{
|
||||
uint8_t value = DragonRuntime::memMap.read8(a);
|
||||
output().fg(ostd::ConsoleColors::BrightRed).p(ostd::Utils::getHexStr(value, true, 1));
|
||||
if (a < end_addr)
|
||||
output().p(" ");
|
||||
}
|
||||
output().fg(ostd::ConsoleColors::Gray).p("]");
|
||||
output().reset().nl();
|
||||
}
|
||||
else if (data().command.startsWith("$"))
|
||||
{
|
||||
uint16_t size = 0;
|
||||
uint16_t addr = Utils::findSymbol(debugger.data, data().command, &size);
|
||||
if (addr == 0)
|
||||
addr = Utils::findSymbol(debugger.labels, data().command, &size);
|
||||
if (addr == 0)
|
||||
output().fg(ostd::ConsoleColors::Red).p("Unknown symbol for <print> command.").reset().nl();
|
||||
else
|
||||
{
|
||||
ostd::String tmp = "";
|
||||
tmp.add("*(").add(ostd::Utils::getHexStr(addr, true, 2));
|
||||
if (type != TYPE_BYTE)
|
||||
if (size > 1)
|
||||
tmp.add("-").add(ostd::Utils::getHexStr((uint16_t)(addr + size - 1), true, 2));
|
||||
tmp.add(")");
|
||||
ostd::RegexRichString rgx(tmp);
|
||||
rgx.fg("\\(|\\)|-", "darkgray");
|
||||
rgx.fg("\\*", "red");
|
||||
rgx.fg("0x[0-9A-Fa-f]+|0b[0-1]+|(?<!\\w)[0-9]+(?!\\w)", "cyan"); //Number Constants
|
||||
output().pStyled(rgx);
|
||||
output().fg(ostd::ConsoleColors::White).p(" = ");
|
||||
output().fg(ostd::ConsoleColors::Gray).p("[");
|
||||
for (uint16_t a = addr; a < addr + size; a++)
|
||||
{
|
||||
uint8_t value = DragonRuntime::memMap.read8(a);
|
||||
output().fg(ostd::ConsoleColors::BrightRed).p(ostd::Utils::getHexStr(value, true, 1));
|
||||
if (a < addr + size - 1)
|
||||
output().p(" ");
|
||||
}
|
||||
output().fg(ostd::ConsoleColors::Gray).p("]");
|
||||
output().reset().nl();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output().fg(ostd::ConsoleColors::Red).p("Invalid value for <print> command.").reset().nl();
|
||||
}
|
||||
Display::printPrompt();
|
||||
data().command = getCommandInput();
|
||||
}
|
||||
else
|
||||
data().command = Display::changeScreen();
|
||||
}
|
||||
return DragonRuntime::RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t Debugger::normal_runtime(bool& outUserQuit)
|
||||
{
|
||||
bool result = DragonRuntime::runStep(data().trackedAddresses);
|
||||
bool hasError = DragonRuntime::hasError();
|
||||
bool enableStepExec = !result || hasError || Utils::isEscapeKeyPressed() || DragonRuntime::cpu.isInDebugBreakPoint();
|
||||
data().args.step_exec = enableStepExec;
|
||||
if (enableStepExec)
|
||||
return step_execution(outUserQuit, false);
|
||||
return DragonRuntime::RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void Debugger::exec_watch_command(void)
|
||||
{
|
||||
auto tokens = data().command.tokenize();
|
||||
for (auto& addr : tokens)
|
||||
{
|
||||
data().command = addr;
|
||||
if (data().command.isNumeric())
|
||||
{
|
||||
data().trackedAddresses.push_back((uint16_t)data().command.toInt());
|
||||
}
|
||||
else if (data().command.startsWith("$"))
|
||||
{
|
||||
uint16_t nbytes = 1;
|
||||
uint16_t addr = Utils::findSymbol(data().data, data().command, &nbytes);
|
||||
if (addr > 0)
|
||||
{
|
||||
for (int32_t i = 0; i < nbytes; i++)
|
||||
data().trackedAddresses.push_back(addr + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = Utils::findSymbol(data().labels, data().command, &nbytes);
|
||||
if (addr > 0)
|
||||
{
|
||||
for (int32_t i = 0; i < nbytes; i++)
|
||||
data().trackedAddresses.push_back(addr + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data().command.contains("[") && data().command.endsWith("]"))
|
||||
{
|
||||
uint16_t nbytes = 1;
|
||||
ostd::String str_nbytes = data().command.new_substr(data().command.indexOf("[") + 1).trim();
|
||||
str_nbytes.substr(0, str_nbytes.len() - 1);
|
||||
data().command.substr(0, data().command.indexOf("[")).trim();
|
||||
if (str_nbytes.isNumeric())
|
||||
nbytes = str_nbytes.toInt();
|
||||
if (nbytes < 1) nbytes = 1;
|
||||
if (data().command.isNumeric())
|
||||
{
|
||||
uint16_t addr = data().command.toInt();
|
||||
for (int32_t i = 0; i < nbytes; i++)
|
||||
data().trackedAddresses.push_back(addr + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
output().p("Tracking ").p((int)data().trackedAddresses.size()).p(" addresses.").nl();
|
||||
}
|
||||
|
||||
void Debugger::print_top_level_prompt_help(void)
|
||||
{
|
||||
int32_t commandLength = 40;
|
||||
Utils::printFullLine('#', ostd::ConsoleColors::Black, ostd::ConsoleColors::Red);
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Yellow).p("List of available commands:").reset().nl();
|
||||
ostd::String tmpCommand = "(r)un";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to start the runtime.").reset().nl();
|
||||
tmpCommand = "(q)uit";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to exit the debugger. (<Escape> key can also be used here.)").reset().nl();
|
||||
tmpCommand = "(h)elp";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to show this dialog.").reset().nl();
|
||||
tmpCommand = "(s)tep";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to enable/disable step-execution for the runtime.").reset().nl();
|
||||
tmpCommand = "(t)rack <address[bytes=1]/symbol>";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to track specific addresses during execution.").reset().nl();
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Cyan).p("The letters in parenthesis can be used as the short version of the command.").nl();
|
||||
out.p("Square brackets represent optional parameters. If they have an '=' and a value, that is the default if not specified.").reset().nl();
|
||||
|
||||
out.nl();
|
||||
Utils::printFullLine('#', ostd::ConsoleColors::Black, ostd::ConsoleColors::Red);
|
||||
}
|
||||
|
||||
void Debugger::print_application_help(void)
|
||||
{
|
||||
int32_t commandLength = 46;
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Yellow).p("List of available parameters:").reset().nl();
|
||||
ostd::String tmpCommand = "--verbose-load";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to show more information while loading the virtual machine.").reset().nl();
|
||||
tmpCommand = "--step-exec";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Launches the debugger directly in step-execution mode.").reset().nl();
|
||||
tmpCommand = "--track-step-diff-off";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Disables the tracking of most machine data used for differential-view.").reset().nl();
|
||||
tmpCommand = "--auto-track-data-off";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Disables the automatic tracking of all data-symbols.").reset().nl();
|
||||
tmpCommand = "--hide-vdisplay";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Hides the Virtual Display during the execution of the program.").reset().nl();
|
||||
tmpCommand = "--auto-start";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Launches the runtime directly, skipping the top-level prompt of the debugger.").reset().nl();
|
||||
tmpCommand = "--force-load <binary-file> <ram-offset>";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Injects the specified binary into RAM at the specified offset.").reset().nl();
|
||||
tmpCommand = "--help";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Displays this help message.").reset().nl();
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Magenta).p("Usage: ./ddb <machine-config-file> [...options...]").reset().nl();
|
||||
out.nl();
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ namespace dragon
|
|||
bool auto_start_debug = false;
|
||||
bool hide_virtual_display = false;
|
||||
bool track_call_stack = true;
|
||||
bool auto_track_all_data_symbols = true;
|
||||
ostd::String force_load_file = "";
|
||||
uint16_t force_load_mem_offset = 0x00;
|
||||
};
|
||||
|
|
@ -38,14 +39,26 @@ namespace dragon
|
|||
bool userQuit { false };
|
||||
ostd::String disassemblyDirectory { "disassembly" };
|
||||
};
|
||||
struct tCloseEventListener : public ostd::BaseObject
|
||||
{
|
||||
void init(void);
|
||||
void handleSignal(ostd::tSignal& signal);
|
||||
inline bool hasHappened(void) const { return m_mainWindowClosed; }
|
||||
|
||||
private:
|
||||
bool m_mainWindowClosed { false };
|
||||
};
|
||||
public: class Utils
|
||||
{
|
||||
public:
|
||||
static DisassemblyList findCodeRegion(const DisassemblyList& code, uint16_t address, uint16_t codeRegionMargin);
|
||||
static ostd::String findSymbol(const DisassemblyList& labels, uint16_t address);
|
||||
static uint16_t findSymbol(const DisassemblyList& labels, const ostd::String& symbol);
|
||||
static ostd::String findSymbol(const DisassemblyList& labels, uint16_t address, uint16_t* outSize = nullptr);
|
||||
static uint16_t findSymbol(const DisassemblyList& labels, const ostd::String& symbol, uint16_t* outSize = nullptr);
|
||||
static bool isValidLabelNameChar(char c);
|
||||
static void clearConsoleLine(void);
|
||||
static bool isEscapeKeyPressed(bool blocking = false);
|
||||
static ostd::ConsoleOutputHandler& printFullLine(char c, const ostd::ConsoleColors::tConsoleColor& foreground);
|
||||
static ostd::ConsoleOutputHandler& printFullLine(char c, const ostd::ConsoleColors::tConsoleColor& foreground, const ostd::ConsoleColors::tConsoleColor& background);
|
||||
};
|
||||
public: class Display
|
||||
{
|
||||
|
|
@ -56,8 +69,9 @@ namespace dragon
|
|||
static void printStep(void);
|
||||
static void printDiff(void);
|
||||
static void printTrackedAddresses(void);
|
||||
static void printStack(void);
|
||||
static void printStack(uint16_t nrows);
|
||||
static void printCallStack(void);
|
||||
static void printHelp(void);
|
||||
static ostd::String changeScreen(void);
|
||||
};
|
||||
public:
|
||||
|
|
@ -67,10 +81,22 @@ namespace dragon
|
|||
static ostd::String getCommandInput(void);
|
||||
static inline tDebuggerData& data(void) { return debugger; }
|
||||
static inline ostd::ConsoleOutputHandler& output(void) { return out; }
|
||||
static int32_t topLevelPrompt(void);
|
||||
static int32_t executeRuntime(void);
|
||||
|
||||
private:
|
||||
static int32_t step_execution(bool& outUserQuit, bool exec_first_step = true);
|
||||
static int32_t normal_runtime(bool& outUserQuit);
|
||||
static void exec_watch_command(void);
|
||||
static void print_top_level_prompt_help(void);
|
||||
static void print_application_help(void);
|
||||
|
||||
private:
|
||||
inline static tDebuggerData debugger;
|
||||
inline static ostd::ConsoleOutputHandler out;
|
||||
inline static std::vector<ostd::String> commandHistory;
|
||||
static tCloseEventListener closeEventListener;
|
||||
|
||||
public:
|
||||
inline static const ostd::String InputCommandQuit = "//quit//";
|
||||
};
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ namespace dragon
|
|||
ostd::serial::SerialIO serializer(stream, ostd::serial::SerialIO::tEndianness::BigEndian);
|
||||
ostd::StreamIndex addr = 0;
|
||||
int32_t line_addr = 0;
|
||||
int16_t data_size = 1;
|
||||
int8_t line_code_char = 0;
|
||||
ostd::String header_string = "";
|
||||
serializer.r_NullTerminatedString(0, header_string);
|
||||
|
|
@ -38,6 +39,8 @@ namespace dragon
|
|||
{
|
||||
serializer.r_DWord(addr, line_addr);
|
||||
addr += ostd::tTypeSize::DWORD;
|
||||
serializer.r_Word(addr, data_size);
|
||||
addr += ostd::tTypeSize::WORD;
|
||||
ostd::String code_line = "";
|
||||
serializer.r_NullTerminatedString(addr, code_line);
|
||||
addr += (code_line.len() + 1) * ostd::tTypeSize::BYTE;
|
||||
|
|
@ -59,6 +62,7 @@ namespace dragon
|
|||
code::Assembler::tDisassemblyLine line;
|
||||
line.addr = line_addr;
|
||||
line.code = code_line;
|
||||
line.size = data_size;
|
||||
if (mode == MODE_CODE)
|
||||
{
|
||||
ostd::String codeEdit(line.code);
|
||||
|
|
|
|||
|
|
@ -1,131 +1,26 @@
|
|||
#include "Debugger.hpp"
|
||||
#include "../runtime/DragonRuntime.hpp"
|
||||
|
||||
void exec_watch_command(void)
|
||||
{
|
||||
using namespace dragon;
|
||||
|
||||
auto tokens = Debugger::data().command.tokenize();
|
||||
for (auto& addr : tokens)
|
||||
{
|
||||
Debugger::data().command = addr;
|
||||
if (Debugger::data().command.isNumeric())
|
||||
Debugger::data().trackedAddresses.push_back((uint16_t)Debugger::data().command.toInt());
|
||||
else if (Debugger::data().command.startsWith("$"))
|
||||
{
|
||||
uint8_t nbytes = 1;
|
||||
if (Debugger::data().command.contains("[") && Debugger::data().command.endsWith("]"))
|
||||
{
|
||||
ostd::String str_nbytes = Debugger::data().command.new_substr(Debugger::data().command.indexOf("[") + 1).trim();
|
||||
str_nbytes.substr(0, str_nbytes.len() - 1);
|
||||
std::cout << str_nbytes << "\n";
|
||||
std::cout << Debugger::data().command << "\n";
|
||||
Debugger::data().command.substr(0, Debugger::data().command.indexOf("[")).trim();
|
||||
std::cout << Debugger::data().command << "\n";
|
||||
if (str_nbytes.isNumeric())
|
||||
nbytes = str_nbytes.toInt();
|
||||
if (nbytes < 1) nbytes = 1;
|
||||
}
|
||||
uint16_t addr = Debugger::Utils::findSymbol(Debugger::data().data, Debugger::data().command);
|
||||
if (addr > 0)
|
||||
{
|
||||
for (int32_t i = 0; i < nbytes; i++)
|
||||
Debugger::data().trackedAddresses.push_back(addr + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = Debugger::Utils::findSymbol(Debugger::data().labels, Debugger::data().command);
|
||||
if (addr > 0)
|
||||
{
|
||||
for (int32_t i = 0; i < nbytes; i++)
|
||||
Debugger::data().trackedAddresses.push_back(addr + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << (int)Debugger::data().trackedAddresses.size() << "\n";
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
using namespace dragon;
|
||||
int32_t rValue = Debugger::loadArguments(argc, argv);
|
||||
if (rValue != 0) return rValue;
|
||||
rValue = Debugger::initRuntime();
|
||||
//Loading commandline arguments
|
||||
int32_t rValue = dragon::Debugger::loadArguments(argc, argv);
|
||||
if (rValue == dragon::DragonRuntime::RETURN_VAL_CLOSE_DEBUGGER)
|
||||
return 0;
|
||||
if (rValue != 0) return rValue;
|
||||
|
||||
//Initializing the runtime
|
||||
rValue = dragon::Debugger::initRuntime();
|
||||
if (rValue == dragon::DragonRuntime::RETURN_VAL_CLOSE_DEBUGGER)
|
||||
return 0;
|
||||
if (rValue != 0) return rValue;
|
||||
|
||||
//Running top-level prompt
|
||||
rValue = dragon::Debugger::topLevelPrompt();
|
||||
if (rValue == dragon::DragonRuntime::RETURN_VAL_CLOSE_DEBUGGER)
|
||||
return 0;
|
||||
if (rValue != 0) return rValue;
|
||||
|
||||
if (!Debugger::data().args.auto_start_debug)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Debugger::Display::printPrompt();
|
||||
Debugger::data().command = Debugger::getCommandInput();
|
||||
Debugger::data().command.trim().toLower();
|
||||
if (Debugger::data().command == "r" || Debugger::data().command == "run")
|
||||
break;
|
||||
else if (Debugger::data().command == "q" || Debugger::data().command == "quit")
|
||||
return rValue;
|
||||
else if (Debugger::data().command.startsWith("watch "))
|
||||
{
|
||||
Debugger::data().command.substr(6).trim();
|
||||
exec_watch_command();
|
||||
}
|
||||
else if (Debugger::data().command == "step")
|
||||
{
|
||||
Debugger::data().args.step_exec = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int32_t labelLineLen = 20;
|
||||
Debugger::data().currentAddress = dragon::DragonRuntime::cpu.readRegister(dragon::data::Registers::IP);
|
||||
|
||||
bool userQuit = false;
|
||||
while (true)
|
||||
{
|
||||
Debugger::data().command.clr();
|
||||
bool result = false;
|
||||
bool hasError = false;
|
||||
if (!userQuit)
|
||||
{
|
||||
result = dragon::DragonRuntime::runStep(Debugger::data().trackedAddresses);
|
||||
hasError = dragon::DragonRuntime::hasError();
|
||||
Debugger::Display::printStep();
|
||||
Debugger::processErrors();
|
||||
}
|
||||
if (!result || userQuit)
|
||||
{
|
||||
Debugger::output().nl().fg(ostd::ConsoleColors::Yellow).p("Execution Finished. Pres <Enter> to exit...").nl().reset();
|
||||
std::cin.get();
|
||||
break;
|
||||
}
|
||||
Debugger::Display::printPrompt();
|
||||
if (Debugger::data().args.step_exec || dragon::DragonRuntime::cpu.isInDebugBreakPoint())
|
||||
{
|
||||
Debugger::data().command = Debugger::getCommandInput();
|
||||
if (dragon::DragonRuntime::cpu.isInDebugBreakPoint())
|
||||
Debugger::data().args.step_exec = true;
|
||||
}
|
||||
Debugger::data().command.trim().toLower();
|
||||
while (Debugger::data().command != "")
|
||||
{
|
||||
if (Debugger::data().command == "q" || Debugger::data().command == "quit")
|
||||
{
|
||||
userQuit = true;
|
||||
Debugger::data().command = "";
|
||||
}
|
||||
else if (Debugger::data().command == "c" || Debugger::data().command == "continue")
|
||||
{
|
||||
Debugger::data().args.step_exec = false;
|
||||
Debugger::data().command = "";
|
||||
}
|
||||
else
|
||||
Debugger::data().command = Debugger::Display::changeScreen();
|
||||
}
|
||||
Debugger::data().currentAddress = dragon::DragonRuntime::cpu.readRegister(dragon::data::Registers::IP);
|
||||
}
|
||||
|
||||
return rValue;
|
||||
//Executing the runtime
|
||||
return dragon::Debugger::executeRuntime();
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ namespace dragon
|
|||
SDL_FreeSurface(m_fontSurface);
|
||||
SDL_DestroyRenderer(m_renderer);
|
||||
SDL_DestroyWindow(m_window);
|
||||
IMG_Quit();
|
||||
// IMG_Quit();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
|
|
@ -23,12 +23,12 @@ namespace dragon
|
|||
printf( "SDL could not initialize! Error: %s\n", SDL_GetError() );
|
||||
exit(1);
|
||||
}
|
||||
int imgFlags = IMG_INIT_PNG;
|
||||
if (!(IMG_Init(imgFlags) & imgFlags))
|
||||
{
|
||||
printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
|
||||
exit(2);
|
||||
}
|
||||
// int imgFlags = IMG_INIT_PNG;
|
||||
// if (!(IMG_Init(imgFlags) & imgFlags))
|
||||
// {
|
||||
// printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
|
||||
// exit(2);
|
||||
// }
|
||||
m_window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_windowWidth, m_windowHeight, SDL_WINDOW_RESIZABLE);
|
||||
SDL_SetWindowResizable(m_window, SDL_FALSE);
|
||||
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED);
|
||||
|
|
@ -122,7 +122,7 @@ namespace dragon
|
|||
SDL_GetWindowSize(m_window, &m_windowWidth, &m_windowHeight);
|
||||
wrd.new_width = m_windowWidth;
|
||||
wrd.new_height = m_windowHeight;
|
||||
ostd::SignalHandler::emitSignal(Signal_OnWindowResized, ostd::tSignalPriority::RealTime, wrd);
|
||||
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::WindowResized, ostd::tSignalPriority::RealTime, wrd);
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_MOUSEMOTION)
|
||||
|
|
@ -131,17 +131,17 @@ namespace dragon
|
|||
if (isMouseDragEventEnabled() && mmd.button != MouseEventData::eButton::None)
|
||||
ostd::SignalHandler::emitSignal(Signal_OnMouseDragged, ostd::tSignalPriority::RealTime, mmd);
|
||||
else
|
||||
ostd::SignalHandler::emitSignal(Signal_OnMouseMoved, ostd::tSignalPriority::RealTime, mmd);
|
||||
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::MouseMoved, ostd::tSignalPriority::RealTime, mmd);
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONDOWN)
|
||||
{
|
||||
MouseEventData mmd = l_getMouseState();
|
||||
ostd::SignalHandler::emitSignal(Signal_OnMousePressed, ostd::tSignalPriority::RealTime, mmd);
|
||||
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::MousePressed, ostd::tSignalPriority::RealTime, mmd);
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONUP)
|
||||
{
|
||||
MouseEventData mmd = l_getMouseState();
|
||||
ostd::SignalHandler::emitSignal(Signal_OnMouseReleased, ostd::tSignalPriority::RealTime, mmd);
|
||||
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::MouseReleased, ostd::tSignalPriority::RealTime, mmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,14 +63,9 @@ namespace dragon
|
|||
bool m_initialized { false };
|
||||
|
||||
public:
|
||||
//Signals
|
||||
inline static const uint32_t Signal_OnMousePressed = ostd::SignalHandler::newCustomSignal(1000);
|
||||
inline static const uint32_t Signal_OnMouseReleased = ostd::SignalHandler::newCustomSignal(1001);
|
||||
inline static const uint32_t Signal_OnMouseMoved = ostd::SignalHandler::newCustomSignal(1002);
|
||||
//Signals //TODO: Add theese to the builtin signals in ostd::SignalHandler
|
||||
inline static const uint32_t Signal_OnMouseDragged = ostd::SignalHandler::newCustomSignal(1003);
|
||||
|
||||
inline static const uint32_t Signal_OnWindowClosed = ostd::SignalHandler::newCustomSignal(2000);
|
||||
inline static const uint32_t Signal_OnWindowResized = ostd::SignalHandler::newCustomSignal(2001);
|
||||
};
|
||||
class WindowResizedData : public ostd::BaseObject
|
||||
{
|
||||
|
|
|
|||
|
|
@ -693,6 +693,16 @@ namespace dragon
|
|||
m_subroutineCounter--;
|
||||
}
|
||||
break;
|
||||
case data::OpCodes::ArgReg:
|
||||
{
|
||||
uint8_t regAddr = fetch8();
|
||||
if (!isInSubRoutine()) break;
|
||||
int16_t pp_val = readRegister(data::Registers::PP);
|
||||
int16_t arg_data = m_memory.read16(pp_val);
|
||||
writeRegister(data::Registers::PP, pp_val - 2);
|
||||
writeRegister(regAddr, arg_data);
|
||||
}
|
||||
break;
|
||||
case data::OpCodes::RetInt:
|
||||
{
|
||||
m_isInInterruptHandler = false;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,64 @@ namespace dragon
|
|||
return list;
|
||||
}
|
||||
|
||||
int32_t DragonRuntime::loadArguments(int argc, char** argv, tCommandLineArgs& args)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: too few arguments.").nl();
|
||||
out.fg(ostd::ConsoleColors::Red).p("Use the --help option for more info.").reset().nl();
|
||||
return dragon::DragonRuntime::RETURN_VAL_TOO_FEW_ARGUMENTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.machine_config_path = argv[1];
|
||||
if (args.machine_config_path == "--help")
|
||||
{
|
||||
__print_application_help();
|
||||
return DragonRuntime::RETURN_VAL_CLOSE_RUNTIME;
|
||||
}
|
||||
for (int32_t i = 2; i < argc; i++)
|
||||
{
|
||||
ostd::String edit(argv[i]);
|
||||
if (edit == "--debug")
|
||||
args.basic_debug = true;
|
||||
else if (edit == "--step")
|
||||
args.step_exec = true;
|
||||
else if (edit == "--verbose-load")
|
||||
args.verbose_load = true;
|
||||
else if (edit == "--limit-cycles")
|
||||
{
|
||||
if (i == argc - 1)
|
||||
return RETURN_VAL_MISSING_PARAM;
|
||||
i++;
|
||||
edit = argv[i];
|
||||
if (!edit.isNumeric())
|
||||
return RETURN_VAL_PARAMETER_NOT_NUMERIC;
|
||||
args.cycle_limit = (int32_t)edit.toInt();
|
||||
}
|
||||
else if (edit == "--force-load")
|
||||
{
|
||||
if ((argc - 1) - i < 2)
|
||||
return RETURN_VAL_MISSING_PARAM;
|
||||
i++;
|
||||
args.force_load_file = argv[i];
|
||||
i++;
|
||||
edit = argv[i];
|
||||
if (!edit.isNumeric())
|
||||
return RETURN_VAL_PARAMETER_NOT_NUMERIC;
|
||||
args.force_load_mem_offset = (uint16_t)edit.toInt();
|
||||
args.force_load = true;
|
||||
}
|
||||
else if (edit == "--help")
|
||||
{
|
||||
__print_application_help();
|
||||
return RETURN_VAL_CLOSE_RUNTIME;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t DragonRuntime::initMachine(const ostd::String& configFilePath,
|
||||
bool verbose,
|
||||
bool trackMachineInfoDiff,
|
||||
|
|
@ -70,13 +128,14 @@ namespace dragon
|
|||
bool trackCallStack,
|
||||
bool debugModeEnabled)
|
||||
{
|
||||
ostd::SignalHandler::init();
|
||||
if (verbose)
|
||||
out.p("Loading machine config: ").p(configFilePath.cpp_str()).nl();
|
||||
out.fg(ostd::ConsoleColors::Magenta).p("Loading machine config: ").fg(ostd::ConsoleColors::BrightYellow).p(configFilePath.cpp_str()).nl();
|
||||
machine_config = dragon::MachineConfigLoader::loadConfig(configFilePath);
|
||||
if (!machine_config.isValid()) return 1; //TODO: Error
|
||||
if (!machine_config.isValid()) return RETURN_VAL_INVALID_MACHINE_CONFIG; //TODO: Error
|
||||
|
||||
if (verbose)
|
||||
out.p(" Initializing virtual display:").nl();
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" Initializing virtual display:").nl();
|
||||
vDisplay.initialize(800, 600, "DragonVM", "font.bmp");
|
||||
int32_t w = RawTextRenderer::CONSOLE_CHARS_H * RawTextRenderer::FONT_CHAR_W; //60 * 16;
|
||||
int32_t h = RawTextRenderer::CONSOLE_CHARS_V * RawTextRenderer::FONT_CHAR_H; //60 * 9;
|
||||
|
|
@ -85,6 +144,7 @@ namespace dragon
|
|||
vDisplay.hide();
|
||||
if (verbose)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(" Done. (").p(w).p("x").p(h).p(")");
|
||||
if (hideVirtualDisplay)
|
||||
out.p(" - HIDDEN").nl();
|
||||
|
|
@ -92,47 +152,50 @@ namespace dragon
|
|||
out.nl();
|
||||
}
|
||||
|
||||
if (machine_config.vdisk_paths.size() == 0) return 2; //TODO: Error
|
||||
if (machine_config.vdisk_paths.size() == 0) return RETURN_VAL_NO_DISK; //TODO: Error
|
||||
if (verbose)
|
||||
out.p(" Initializing virtual disks:").nl();
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" Initializing virtual disks:").nl();
|
||||
for (auto const& disk_path : machine_config.vdisk_paths)
|
||||
{
|
||||
vDisks[disk_path.first] = dragon::hw::VirtualHardDrive(disk_path.second);
|
||||
vDiskInterface.connectDisk(vDisks[disk_path.first]);
|
||||
if (verbose)
|
||||
out.p(" Disk").p(disk_path.first).p(" connected: ").p(disk_path.second.cpp_str()).nl();
|
||||
out.fg(ostd::ConsoleColors::BrightYellow).p(" Disk").p(disk_path.first).p(" connected: ").p(disk_path.second.cpp_str()).nl();
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
out.p(" Loading vBIOS file: ").p(machine_config.bios_path.cpp_str()).nl();
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" Loading vBIOS file: ").fg(ostd::ConsoleColors::BrightYellow).p(machine_config.bios_path.cpp_str()).nl();
|
||||
vBIOS.init(machine_config.bios_path);
|
||||
|
||||
if (verbose)
|
||||
out.p(" Loading vCMOS file: ").p(machine_config.cmos_path.cpp_str()).nl();
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" Loading vCMOS file: ").fg(ostd::ConsoleColors::BrightYellow).p(machine_config.cmos_path.cpp_str()).nl();
|
||||
vCMOS.init(machine_config.cmos_path);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" Initializing Memory Mapper:").nl();
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" Initializing Memory Mapper:").nl();
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(" vBIOS: ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::BIOS_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::BIOS_End, true, 2).cpp_str());
|
||||
out.p(" (remap=false)").nl();
|
||||
}
|
||||
memMap.mapDevice(vBIOS, dragon::data::MemoryMapAddresses::BIOS_Start, dragon::data::MemoryMapAddresses::BIOS_End, false, "vBIOS");
|
||||
memMap.mapDevice(vBIOS, dragon::data::MemoryMapAddresses::BIOS_Start, dragon::data::MemoryMapAddresses::BIOS_End, false, "BIOS");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" vCMOS: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).fg(ostd::ConsoleColors::Magenta).p(" vCMOS: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::CMOS_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::CMOS_End, true, 2).cpp_str());
|
||||
out.p(" (remap=true)").nl();
|
||||
}
|
||||
memMap.mapDevice(vCMOS, dragon::data::MemoryMapAddresses::CMOS_Start, dragon::data::MemoryMapAddresses::CMOS_End, true, "vCMOS");
|
||||
memMap.mapDevice(vCMOS, dragon::data::MemoryMapAddresses::CMOS_Start, dragon::data::MemoryMapAddresses::CMOS_End, true, "CMOS");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" intVec: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" intVec: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::IntVector_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::IntVector_End, true, 2).cpp_str());
|
||||
|
|
@ -141,61 +204,68 @@ namespace dragon
|
|||
memMap.mapDevice(intVec, dragon::data::MemoryMapAddresses::IntVector_Start, dragon::data::MemoryMapAddresses::IntVector_End, true, "intVec");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" vKeyboard: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" vKeyboard: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::Keyboard_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::Keyboard_End, true, 2).cpp_str());
|
||||
out.p(" (remap=false)").nl();
|
||||
}
|
||||
memMap.mapDevice(vKeyboard, dragon::data::MemoryMapAddresses::Keyboard_Start, dragon::data::MemoryMapAddresses::Keyboard_End, false, "vKeyboard");
|
||||
memMap.mapDevice(vKeyboard, dragon::data::MemoryMapAddresses::Keyboard_Start, dragon::data::MemoryMapAddresses::Keyboard_End, false, "Keyb.");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" vMouse: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" vMouse: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::Mouse_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::Mouse_End, true, 2).cpp_str());
|
||||
out.p(" (remap=false)").nl();
|
||||
}
|
||||
memMap.mapDevice(vMouse, dragon::data::MemoryMapAddresses::Mouse_Start, dragon::data::MemoryMapAddresses::Mouse_End, false, "vMouse");
|
||||
memMap.mapDevice(vMouse, dragon::data::MemoryMapAddresses::Mouse_Start, dragon::data::MemoryMapAddresses::Mouse_End, false, "Mouse");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" vMBR: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" vMBR: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::MBR_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::MBR_End, true, 2).cpp_str());
|
||||
out.p(" (remap=true)").nl();
|
||||
}
|
||||
memMap.mapDevice(vMBR, dragon::data::MemoryMapAddresses::MBR_Start, dragon::data::MemoryMapAddresses::MBR_End, true, "vMBR");
|
||||
memMap.mapDevice(vMBR, dragon::data::MemoryMapAddresses::MBR_Start, dragon::data::MemoryMapAddresses::MBR_End, true, "MBR");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" vDiskInterface: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" vDiskInterface: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::DiskInterface_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::DiskInterface_End, true, 2).cpp_str());
|
||||
out.p(" (remap=true)").nl();
|
||||
}
|
||||
memMap.mapDevice(vDiskInterface, dragon::data::MemoryMapAddresses::DiskInterface_Start, dragon::data::MemoryMapAddresses::DiskInterface_End, true, "vDiskInterface");
|
||||
memMap.mapDevice(vDiskInterface, dragon::data::MemoryMapAddresses::DiskInterface_Start, dragon::data::MemoryMapAddresses::DiskInterface_End, true, "Disk");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" vGraphicsInterface: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" vGraphicsInterface: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::VideoCardInterface_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::VideoCardInterface_End, true, 2).cpp_str());
|
||||
out.p(" (remap=true)").nl();
|
||||
}
|
||||
memMap.mapDevice(vGraphicsInterface, dragon::data::MemoryMapAddresses::VideoCardInterface_Start, dragon::data::MemoryMapAddresses::VideoCardInterface_End, true, "vGraphicsInterface");
|
||||
memMap.mapDevice(vGraphicsInterface, dragon::data::MemoryMapAddresses::VideoCardInterface_Start, dragon::data::MemoryMapAddresses::VideoCardInterface_End, true, "VGA");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" vSerialInterface: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" vSerialInterface: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::SerialInterface_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::SerialInterface_End, true, 2).cpp_str());
|
||||
out.p(" (remap=true)").nl();
|
||||
}
|
||||
memMap.mapDevice(vSerialInterface, dragon::data::MemoryMapAddresses::SerialInterface_Start, dragon::data::MemoryMapAddresses::SerialInterface_End, true, "vSerialInterface");
|
||||
memMap.mapDevice(vSerialInterface, dragon::data::MemoryMapAddresses::SerialInterface_Start, dragon::data::MemoryMapAddresses::SerialInterface_End, true, "serial");
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" RAM: ");
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" RAM: ");
|
||||
out.fg(ostd::ConsoleColors::BrightYellow);
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::Memory_Start, true, 2).cpp_str());
|
||||
out.p(" to ");
|
||||
out.p(ostd::Utils::getHexStr(dragon::data::MemoryMapAddresses::Memory_End, true, 2).cpp_str());
|
||||
|
|
@ -207,24 +277,24 @@ namespace dragon
|
|||
uint8_t default_bios_video_color = 0x4;
|
||||
if (verbose)
|
||||
{
|
||||
out.p(" Initializing vCPU reset sequence:").nl();
|
||||
out.fg(ostd::ConsoleColors::Magenta).p(" Initializing vCPU reset sequence:").nl();
|
||||
// out.p(" BIOSVideo default colors: ").p(ostd::Utils::getHexStr(default_bios_video_color).cpp_str()).nl();
|
||||
}
|
||||
// memMap.write8(dragon::data::MemoryMapAddresses::BIOSVideo_Start, default_bios_video_color);
|
||||
|
||||
uint16_t reset_ip_addr = 0x0000;
|
||||
if (verbose)
|
||||
out.p(" Reset IP register: ").p(ostd::Utils::getHexStr(reset_ip_addr, true, 2).cpp_str()).nl();
|
||||
out.fg(ostd::ConsoleColors::BrightYellow).p(" Reset IP register: ").p(ostd::Utils::getHexStr(reset_ip_addr, true, 2).cpp_str()).nl();
|
||||
cpu.writeRegister(dragon::data::Registers::IP, reset_ip_addr);
|
||||
|
||||
if (verbose)
|
||||
out.p(" Debug mode enabled: ").p(STR_BOOL(debugModeEnabled)).nl();
|
||||
out.fg(ostd::ConsoleColors::BrightYellow).p(" Debug mode enabled: ").p(STR_BOOL(debugModeEnabled)).nl();
|
||||
cpu.m_debugModeEnabled = debugModeEnabled;
|
||||
|
||||
out.nl().nl();
|
||||
s_trackMachineInfo = trackMachineInfoDiff;
|
||||
s_trackCallStack = trackCallStack;
|
||||
return 0;
|
||||
return RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void DragonRuntime::runMachine(int32_t cycleLimit, bool basic_debug, bool step_exec)
|
||||
|
|
@ -239,6 +309,7 @@ namespace dragon
|
|||
{
|
||||
if (basic_debug)
|
||||
out.clear();
|
||||
ostd::SignalHandler::refresh();
|
||||
uint16_t addr = cpu.readRegister(dragon::data::Registers::IP);
|
||||
uint16_t spAddr = cpu.readRegister(dragon::data::Registers::SP);
|
||||
running = cpu.execute() && vDisplay.isRunning();
|
||||
|
|
@ -283,6 +354,7 @@ namespace dragon
|
|||
|
||||
bool DragonRuntime::runStep(std::vector<uint16_t> trackedAddresses)
|
||||
{
|
||||
std::sort(trackedAddresses.begin(), trackedAddresses.end());
|
||||
__get_machine_footprint(&s_machineInfo, trackedAddresses, true);
|
||||
__track_call_stack(&s_machineInfo);
|
||||
bool running = cpu.execute() && vDisplay.isRunning();
|
||||
|
|
@ -404,26 +476,54 @@ namespace dragon
|
|||
if (inst == data::OpCodes::CallImm)
|
||||
{
|
||||
uint16_t call_addr = memMap.read16(instAddr + 1);
|
||||
minfo.callStack.push_back({ "CALL IMM", call_addr });
|
||||
minfo.callStack.push_back({ "CALL IMM", call_addr, instAddr });
|
||||
}
|
||||
else if (inst == data::OpCodes::CallReg)
|
||||
{
|
||||
uint8_t reg_addr = memMap.read8(instAddr + 1);
|
||||
uint16_t call_addr = cpu.readRegister(reg_addr);
|
||||
minfo.callStack.push_back({ "CALL REG", call_addr });
|
||||
minfo.callStack.push_back({ "CALL REG", call_addr, instAddr });
|
||||
}
|
||||
else if (interrupts_enabled && inst == data::OpCodes::Int)
|
||||
{
|
||||
uint8_t int_num = memMap.read8(instAddr + 1);
|
||||
minfo.callStack.push_back({ "INT", int_num });
|
||||
minfo.callStack.push_back({ "INT", int_num, instAddr });
|
||||
}
|
||||
else if (inst == data::OpCodes::Ret)
|
||||
{
|
||||
minfo.callStack.push_back({ "RET", 0x0000 });
|
||||
minfo.callStack.push_back({ "RET", 0x0000, instAddr });
|
||||
}
|
||||
else if (interrupts_enabled && inst == data::OpCodes::RetInt)
|
||||
{
|
||||
minfo.callStack.push_back({ "RET INT", 0x0000 });
|
||||
minfo.callStack.push_back({ "RET INT", 0x0000, instAddr });
|
||||
}
|
||||
}
|
||||
|
||||
void DragonRuntime::__print_application_help(void)
|
||||
{
|
||||
int32_t commandLength = 46;
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Yellow).p("List of available parameters:").reset().nl();
|
||||
ostd::String tmpCommand = "--verbose-load";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to show more information while loading the virtual machine.").reset().nl();
|
||||
tmpCommand = "--step";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Launches the runtime in basic step-esecution mode.").reset().nl();
|
||||
tmpCommand = "--debug";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Launches the runtime in basic debug mode.").reset().nl();
|
||||
tmpCommand = "--limit-cycles <cycles>";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Sets the maximum amount of clock cycles the runtime can run.").reset().nl();
|
||||
tmpCommand = "--force-load <binary-file> <ram-offset>";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Injects the specified binary into RAM at the specified offset.").reset().nl();
|
||||
tmpCommand = "--help";
|
||||
tmpCommand.addRightPadding(commandLength);
|
||||
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Displays this help message.").reset().nl();
|
||||
|
||||
out.nl().fg(ostd::ConsoleColors::Magenta).p("Usage: ./dvm <machine-config-file> [...options...]").reset().nl();
|
||||
out.nl();
|
||||
}
|
||||
}
|
||||
|
|
@ -16,12 +16,25 @@ namespace dragon
|
|||
{
|
||||
class DragonRuntime
|
||||
{
|
||||
public: struct tCallInfo {
|
||||
public: struct tCallInfo
|
||||
{
|
||||
ostd::String info;
|
||||
uint16_t addr;
|
||||
uint16_t inst_addr;
|
||||
};
|
||||
|
||||
public: struct tMachineDebugInfo {
|
||||
public: struct tCommandLineArgs
|
||||
{
|
||||
ostd::String machine_config_path = "";
|
||||
bool basic_debug = false;
|
||||
bool step_exec = false;
|
||||
bool verbose_load = false;
|
||||
int32_t cycle_limit = 0;
|
||||
bool force_load = false;
|
||||
ostd::String force_load_file = "";
|
||||
uint16_t force_load_mem_offset = 0x00;
|
||||
};
|
||||
public: struct tMachineDebugInfo
|
||||
{
|
||||
inline tMachineDebugInfo(void) { }
|
||||
|
||||
uint16_t previousInstructionAddress { 0x0000 };
|
||||
|
|
@ -63,6 +76,7 @@ namespace dragon
|
|||
static void printRegisters(dragon::hw::VirtualCPU& cpu);
|
||||
static void processErrors(void);
|
||||
static std::vector<data::ErrorHandler::tError> getErrorList(void);
|
||||
static int32_t loadArguments(int argc, char** argv, tCommandLineArgs& args);
|
||||
static int32_t initMachine(const ostd::String& configFilePath,
|
||||
bool verbose = false,
|
||||
bool trackMachineInfoDiff = false,
|
||||
|
|
@ -75,10 +89,12 @@ namespace dragon
|
|||
|
||||
inline static const tMachineDebugInfo& getMachineInfoDiff(void) { return s_machineInfo; }
|
||||
inline static bool hasError(void) { return data::ErrorHandler::hasError(); }
|
||||
inline static ostd::ConsoleOutputHandler& output(void) { return out; }
|
||||
|
||||
private:
|
||||
static void __get_machine_footprint(tMachineDebugInfo* machineInfo, std::vector<uint16_t> trackedAddresses, bool previous);
|
||||
static void __track_call_stack(tMachineDebugInfo* machineInfo);
|
||||
static void __print_application_help(void);
|
||||
|
||||
public:
|
||||
inline static ostd::ConsoleOutputHandler out;
|
||||
|
|
@ -106,5 +122,15 @@ namespace dragon
|
|||
inline static tMachineDebugInfo s_machineInfo;
|
||||
inline static bool s_trackMachineInfo { false };
|
||||
inline static bool s_trackCallStack { false };
|
||||
|
||||
public:
|
||||
inline static const int32_t RETURN_VAL_CLOSE_DEBUGGER = 128;
|
||||
inline static const int32_t RETURN_VAL_CLOSE_RUNTIME = 256;
|
||||
inline static const int32_t RETURN_VAL_INVALID_MACHINE_CONFIG = 1;
|
||||
inline static const int32_t RETURN_VAL_NO_DISK = 2;
|
||||
inline static const int32_t RETURN_VAL_TOO_FEW_ARGUMENTS = 3;
|
||||
inline static const int32_t RETURN_VAL_MISSING_PARAM = 4;
|
||||
inline static const int32_t RETURN_VAL_PARAMETER_NOT_NUMERIC = 5;
|
||||
inline static const int32_t RETURN_VAL_EXIT_SUCCESS = 0;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,74 +1,24 @@
|
|||
#include <ostd/Utils.hpp>
|
||||
|
||||
#include "DragonRuntime.hpp"
|
||||
|
||||
ostd::ConsoleOutputHandler out;
|
||||
|
||||
struct tCommandLineArgs
|
||||
{
|
||||
ostd::String machine_config_path = "";
|
||||
bool basic_debug = false;
|
||||
bool step_exec = false;
|
||||
bool verbose_load = false;
|
||||
int32_t cycle_limit = 0;
|
||||
bool force_load = false;
|
||||
ostd::String force_load_file = "";
|
||||
uint16_t force_load_mem_offset = 0x00;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
tCommandLineArgs args;
|
||||
if (argc < 2)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error, too few arguments.").reset().nl();
|
||||
return 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.machine_config_path = argv[1];
|
||||
for (int32_t i = 2; i < argc; i++)
|
||||
{
|
||||
ostd::String edit(argv[i]);
|
||||
if (edit == "--debug")
|
||||
args.basic_debug = true;
|
||||
else if (edit == "--step")
|
||||
args.step_exec = true;
|
||||
else if (edit == "--verbose-load")
|
||||
args.verbose_load = true;
|
||||
else if (edit == "--limit-cycles")
|
||||
{
|
||||
if (i == argc - 1)
|
||||
break; //TODO: Warning
|
||||
i++;
|
||||
edit = argv[i];
|
||||
if (!edit.isNumeric())
|
||||
continue; //TODO: Error
|
||||
args.cycle_limit = (int32_t)edit.toInt();
|
||||
}
|
||||
else if (edit == "--force-load")
|
||||
{
|
||||
if ((argc - 1) - i < 2)
|
||||
break; //TODO: Warning
|
||||
i++;
|
||||
args.force_load_file = argv[i];
|
||||
i++;
|
||||
edit = argv[i];
|
||||
if (!edit.isNumeric())
|
||||
continue; //TODO: Error
|
||||
args.force_load_mem_offset = (uint16_t)edit.toInt();
|
||||
args.force_load = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Loading commandline arguments
|
||||
dragon::DragonRuntime::tCommandLineArgs args;
|
||||
int32_t rValue = dragon::DragonRuntime::loadArguments(argc, argv, args);
|
||||
if (rValue == dragon::DragonRuntime::RETURN_VAL_CLOSE_RUNTIME)
|
||||
return 0;
|
||||
if (rValue != 0) return rValue;
|
||||
|
||||
int32_t init_state = dragon::DragonRuntime::initMachine(args.machine_config_path, args.verbose_load);
|
||||
if (init_state != 0) return init_state; //TODO: Error
|
||||
//Initializing the runtime
|
||||
rValue = dragon::DragonRuntime::initMachine(args.machine_config_path, args.verbose_load);
|
||||
if (rValue == dragon::DragonRuntime::RETURN_VAL_CLOSE_RUNTIME)
|
||||
return 0;
|
||||
if (rValue != 0) return rValue;
|
||||
|
||||
//Executing the runtime
|
||||
if (args.force_load)
|
||||
dragon::DragonRuntime::forceLoad(args.force_load_file, args.force_load_mem_offset);
|
||||
|
||||
dragon::DragonRuntime::runMachine(args.cycle_limit, args.basic_debug, args.step_exec);
|
||||
|
||||
return 0;
|
||||
return dragon::DragonRuntime::RETURN_VAL_EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ namespace dragon
|
|||
inline static constexpr uint8_t CallImm = 0x53;
|
||||
inline static constexpr uint8_t CallReg = 0x54;
|
||||
inline static constexpr uint8_t Ret = 0x55;
|
||||
inline static constexpr uint8_t ArgReg = 0x56;
|
||||
|
||||
inline static constexpr uint8_t LShiftRegImm = 0x60;
|
||||
inline static constexpr uint8_t LShiftRegReg = 0x61;
|
||||
|
|
@ -337,6 +338,7 @@ namespace dragon
|
|||
case data::OpCodes::CallImm: return "CallImm";
|
||||
case data::OpCodes::CallReg: return "CallReg";
|
||||
case data::OpCodes::Ret: return "Ret";
|
||||
case data::OpCodes::ArgReg: return "ArgReg";
|
||||
case data::OpCodes::RetInt: return "RetInt";
|
||||
case data::OpCodes::Int: return "Int";
|
||||
default: return "UNKNOWN_INST";
|
||||
|
|
@ -410,6 +412,7 @@ namespace dragon
|
|||
case data::OpCodes::CallImm: return 3;
|
||||
case data::OpCodes::CallReg: return 2;
|
||||
case data::OpCodes::Ret: return 1;
|
||||
case data::OpCodes::ArgReg: return 2;
|
||||
case data::OpCodes::RetInt: return 1;
|
||||
case data::OpCodes::Int: return 2;
|
||||
default: return 0;
|
||||
|
|
|
|||
|
|
@ -5,4 +5,3 @@
|
|||
#endif
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
156
src/tools/Tools.cpp
Normal file
156
src/tools/Tools.cpp
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#include "Tools.hpp"
|
||||
|
||||
#include <ostd/Utils.hpp>
|
||||
#include <fstream>
|
||||
#include "../hardware/VirtualHardDrive.hpp"
|
||||
|
||||
namespace dragon
|
||||
{
|
||||
bool Tools::createVirtualHardDrive(uint32_t sizeInBytes, const ostd::String& dataFilePath)
|
||||
{
|
||||
std::ofstream rf(dataFilePath.cpp_str(), std::ios::out | std::ios::binary);
|
||||
if(!rf) return false;
|
||||
ostd::ByteStream stream;
|
||||
for (int32_t i = 0; i < sizeInBytes; i++)
|
||||
stream.push_back(0x00);
|
||||
rf.write((char*)(&stream[0]), stream.size());
|
||||
rf.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t Tools::execute(int argc, char** argv)
|
||||
{
|
||||
ostd::String tool = "";
|
||||
int32_t rValue = get_tool(argc, argv, tool);
|
||||
if (rValue != ErrorNoError)
|
||||
return rValue;
|
||||
|
||||
if (tool == "new-vdisk")
|
||||
{
|
||||
rValue = tool_new_virtual_disk(argc, argv);
|
||||
if (rValue != ErrorNoError)
|
||||
return rValue;
|
||||
}
|
||||
else if (tool == "load-binary")
|
||||
{
|
||||
rValue = tool_load_binary(argc, argv);
|
||||
if (rValue != ErrorNoError)
|
||||
return rValue;
|
||||
}
|
||||
else if (tool == "--help")
|
||||
{
|
||||
print_application_help();
|
||||
return ErrorNoError;
|
||||
}
|
||||
else
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: Unknown tool.").reset().nl();
|
||||
out.fg(ostd::ConsoleColors::Red).p("Use the --help option for more info.").reset().nl();
|
||||
return ErrorTopLevelUnknownTool;
|
||||
}
|
||||
return ErrorNoError;
|
||||
}
|
||||
|
||||
int32_t Tools::tool_new_virtual_disk(int argc, char** argv)
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: too few arguments.").nl();
|
||||
out.fg(ostd::ConsoleColors::Red).p(" Usage: ./dtools new-vdisk <destination_file> <size_in_bytes>").reset().nl();
|
||||
return ErrorNewVDiskTooFewArgs;
|
||||
}
|
||||
ostd::String dest = argv[2];
|
||||
ostd::String str_size = argv[3];
|
||||
if (!ostd::Utils::isInt(str_size))
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: <size_in_bytes> parameter must be integer.").reset().nl();
|
||||
return ErrorNewVDiskNonIntSize;
|
||||
}
|
||||
bool result = createVirtualHardDrive(ostd::Utils::strToInt(str_size), dest);
|
||||
if (!result)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: Unable to create virtual disk.").reset().nl();
|
||||
return ErrorNewVDiskUnable;
|
||||
}
|
||||
out.nl().fg(ostd::ConsoleColors::Green).p("Success. Virtual disk created:").nl();
|
||||
out.p(" Path: ").p(dest.cpp_str()).nl();
|
||||
out.p(" Size: ").p(str_size.cpp_str()).reset().nl();
|
||||
return ErrorNoError;
|
||||
}
|
||||
|
||||
int32_t Tools::tool_load_binary(int argc, char** argv)
|
||||
{
|
||||
if (argc < 5)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: too few arguments.").nl();
|
||||
out.fg(ostd::ConsoleColors::Red).p(" Usage: ./dtools load-binary <virtual_disk_file> <data_file> <destination_address>").reset().nl();
|
||||
return ErrorLoadProgTooFewArgs;
|
||||
}
|
||||
ostd::String vdisk_file = argv[2];
|
||||
ostd::String data_file = argv[3];
|
||||
ostd::String str_addr = argv[4];
|
||||
if (!ostd::Utils::isInt(str_addr))
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: <destination_address> parameter must be integer.").reset().nl();
|
||||
return ErrorLoadProgNonIntAddr;
|
||||
}
|
||||
dragon::hw::VirtualHardDrive vHDD(vdisk_file);
|
||||
if (!vHDD.isInitialized())
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: Unable to load virtual disk.").reset().nl();
|
||||
return ErrorLoadProgUnableToLoadVDisk;
|
||||
}
|
||||
ostd::ByteStream code;
|
||||
if (!ostd::Utils::loadByteStreamFromFile(data_file, code))
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: Unable to load data file.").reset().nl();
|
||||
return ErrorLoadProgUnableToLoadDataFile;
|
||||
}
|
||||
int16_t index = 0;
|
||||
uint32_t addr = (uint32_t)ostd::Utils::strToInt(str_addr);
|
||||
for (auto& b : code)
|
||||
{
|
||||
vHDD.write(addr + index, b);
|
||||
index++;
|
||||
}
|
||||
vHDD.unmount();
|
||||
out.nl().fg(ostd::ConsoleColors::Green).p("Success. Data writte to Virtual Disk:").nl();
|
||||
out.p(" Data Path: ").p(data_file.cpp_str()).nl();
|
||||
out.p(" Disk Path: ").p(vdisk_file.cpp_str()).nl();
|
||||
out.p(" Data Address: ").p(ostd::Utils::getHexStr(addr, true, 4).cpp_str()).nl();
|
||||
out.p(" Size: ").p(code.size()).reset().nl();
|
||||
return ErrorNoError;
|
||||
}
|
||||
|
||||
void Tools::print_application_help(void)
|
||||
{
|
||||
out.nl().fg(ostd::ConsoleColors::Yellow).p("List of available tools:").nl().nl();
|
||||
|
||||
out.fg(ostd::ConsoleColors::Blue).p("load-binary <virtual_disk_file> <data_file> <destination_address>").nl();
|
||||
out.fg(ostd::ConsoleColors::Green).p("The <load-binary> tool is used to load a binary file directly into a Virtual Disk.").nl();
|
||||
out.p(" <virtual_disk_file> Path to the destination Virtual Disk file.").nl();
|
||||
out.p(" <data_file> Path to the source binary file.").nl();
|
||||
out.p(" <destination_address> Destination address on the Virtual Disk.").nl().nl();
|
||||
|
||||
out.fg(ostd::ConsoleColors::Blue).p("new-vdisk <destination_file> <size_in_bytes>").nl();
|
||||
out.fg(ostd::ConsoleColors::Green).p("The <new-vdisk> tool is used to create a new Virtual Disk File.").nl();
|
||||
out.p(" <destination_file> Path of the destination Virtual Disk file to be created.").nl();
|
||||
out.p(" <size_in_bytes> Size of the new Virtual Disk file, in bytes .").nl().nl();
|
||||
|
||||
out.fg(ostd::ConsoleColors::Magenta).p("Usage: ./dtools <tool_name> [...arguments...]").nl().nl().reset();
|
||||
}
|
||||
|
||||
int32_t Tools::get_tool(int argc, char** argv, ostd::String& outTool)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
out.fg(ostd::ConsoleColors::Red).p("Error: too few arguments.").nl();
|
||||
out.fg(ostd::ConsoleColors::Red).p("Use the --help option for more info.").reset().nl();
|
||||
return ErrorTopLevelTooFewArgs;
|
||||
}
|
||||
ostd::String tool = argv[1];
|
||||
tool = tool.trim().toLower();
|
||||
outTool = tool;
|
||||
return ErrorNoError;
|
||||
}
|
||||
}
|
||||
35
src/tools/Tools.hpp
Normal file
35
src/tools/Tools.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <ostd/IOHandlers.hpp>
|
||||
|
||||
namespace dragon
|
||||
{
|
||||
class Tools
|
||||
{
|
||||
public:
|
||||
static inline ostd::ConsoleOutputHandler& output(void) { return out; }
|
||||
static bool createVirtualHardDrive(uint32_t sizeInBytes, const ostd::String& dataFilePath);
|
||||
static int32_t execute(int argc, char** argv);
|
||||
|
||||
private:
|
||||
static int32_t tool_new_virtual_disk(int argc, char** argv);
|
||||
static int32_t tool_load_binary(int argc, char** argv);
|
||||
static void print_application_help(void);
|
||||
static int32_t get_tool(int argc, char** argv, ostd::String& outTool);
|
||||
|
||||
private:
|
||||
inline static ostd::ConsoleOutputHandler out;
|
||||
|
||||
public:
|
||||
inline static constexpr int32_t ErrorNoError = 0;
|
||||
inline static constexpr int32_t ErrorTopLevelTooFewArgs = 1;
|
||||
inline static constexpr int32_t ErrorTopLevelUnknownTool = 2;
|
||||
inline static constexpr int32_t ErrorNewVDiskTooFewArgs = 3;
|
||||
inline static constexpr int32_t ErrorNewVDiskNonIntSize = 4;
|
||||
inline static constexpr int32_t ErrorNewVDiskUnable = 5;
|
||||
inline static constexpr int32_t ErrorLoadProgTooFewArgs = 6;
|
||||
inline static constexpr int32_t ErrorLoadProgNonIntAddr = 7;
|
||||
inline static constexpr int32_t ErrorLoadProgUnableToLoadVDisk = 8;
|
||||
inline static constexpr int32_t ErrorLoadProgUnableToLoadDataFile = 9;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,122 +1,6 @@
|
|||
#include <ostd/Utils.hpp>
|
||||
#include <fstream>
|
||||
#include <ostd/IOHandlers.hpp>
|
||||
|
||||
#include "../hardware/VirtualHardDrive.hpp"
|
||||
|
||||
constexpr int ErrorTopLevelTooFewArgs = 1;
|
||||
constexpr int ErrorTopLevelUnknownTool = 4;
|
||||
|
||||
constexpr int ErrorNewVDiskTooFewArgs = 2;
|
||||
constexpr int ErrorNewVDiskNonIntSize = 3;
|
||||
constexpr int ErrorNewVDiskUnable = 5;
|
||||
|
||||
constexpr int ErrorLoadProgTooFewArgs = 6;
|
||||
constexpr int ErrorLoadProgNonIntAddr = 7;
|
||||
constexpr int ErrorLoadProgUnableToLoadVDisk = 8;
|
||||
constexpr int ErrorLoadProgUnableToLoadDataFile = 8;
|
||||
|
||||
constexpr int ErrorNoError = 0;
|
||||
|
||||
ostd::ConsoleOutputHandler out;
|
||||
|
||||
bool createVirtualHardDrive(uint32_t sizeInBytes, const ostd::String& dataFilePath)
|
||||
{
|
||||
std::ofstream rf(dataFilePath.cpp_str(), std::ios::out | std::ios::binary);
|
||||
if(!rf) return false;
|
||||
ostd::ByteStream stream;
|
||||
for (int32_t i = 0; i < sizeInBytes; i++)
|
||||
stream.push_back(0x00);
|
||||
rf.write((char*)(&stream[0]), stream.size());
|
||||
rf.close();
|
||||
return true;
|
||||
}
|
||||
#include "Tools.hpp"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
out.fg("red").p("Error: too few arguments.").nl();
|
||||
out.fg("red").p(" Usage: ./dtools <tool_name> [...arguments...]").reset().nl();
|
||||
return ErrorTopLevelTooFewArgs;
|
||||
}
|
||||
ostd::String tool = argv[1];
|
||||
tool = tool.trim().toLower();
|
||||
|
||||
//Nex Virtual Disk
|
||||
if (tool == "new-vdisk")
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
out.fg("red").p("Error: too few arguments.").nl();
|
||||
out.fg("red").p(" Usage: ./dtools new-vdisk <destination_file> <size_in_bytes>").reset().nl();
|
||||
return ErrorNewVDiskTooFewArgs;
|
||||
}
|
||||
ostd::String dest = argv[2];
|
||||
ostd::String str_size = argv[3];
|
||||
if (!ostd::Utils::isInt(str_size))
|
||||
{
|
||||
out.fg("red").p("Error: <size_in_bytes> parameter must be integer.").reset().nl();
|
||||
return ErrorNewVDiskNonIntSize;
|
||||
}
|
||||
bool result = createVirtualHardDrive(ostd::Utils::strToInt(str_size), dest);
|
||||
if (!result)
|
||||
{
|
||||
out.fg("red").p("Error: Unable to create virtual disk.").reset().nl();
|
||||
return ErrorNewVDiskUnable;
|
||||
}
|
||||
out.fg("green").p("Success. Virtual disk created:").nl();
|
||||
out.p(" Path: ").p(dest.cpp_str()).nl();
|
||||
out.p(" Size: ").p(str_size.cpp_str()).reset().nl();
|
||||
}
|
||||
//Load Program
|
||||
else if (tool == "load-program")
|
||||
{
|
||||
if (argc < 5)
|
||||
{
|
||||
out.fg("red").p("Error: too few arguments.").nl();
|
||||
out.fg("red").p(" Usage: ./dtools load-program <virtual_disk_file> <data_file> <destination_address>").reset().nl();
|
||||
return ErrorLoadProgTooFewArgs;
|
||||
}
|
||||
ostd::String vdisk_file = argv[2];
|
||||
ostd::String data_file = argv[3];
|
||||
ostd::String str_addr = argv[4];
|
||||
if (!ostd::Utils::isInt(str_addr))
|
||||
{
|
||||
out.fg("red").p("Error: <destination_address> parameter must be integer.").reset().nl();
|
||||
return ErrorLoadProgNonIntAddr;
|
||||
}
|
||||
dragon::hw::VirtualHardDrive vHDD(vdisk_file);
|
||||
if (!vHDD.isInitialized())
|
||||
{
|
||||
out.fg("red").p("Error: Unable to load virtual disk.").reset().nl();
|
||||
return ErrorLoadProgUnableToLoadVDisk;
|
||||
}
|
||||
ostd::ByteStream code;
|
||||
if (!ostd::Utils::loadByteStreamFromFile(data_file, code))
|
||||
{
|
||||
out.fg("red").p("Error: Unable to load data file.").reset().nl();
|
||||
return ErrorLoadProgUnableToLoadDataFile;
|
||||
}
|
||||
int16_t index = 0;
|
||||
uint32_t addr = (uint32_t)ostd::Utils::strToInt(str_addr);
|
||||
for (auto& b : code)
|
||||
{
|
||||
vHDD.write(addr + index, b);
|
||||
index++;
|
||||
}
|
||||
vHDD.unmount();
|
||||
out.fg("green").p("Success. Data writte to Virtual Disk:").nl();
|
||||
out.p(" Data Path: ").p(data_file.cpp_str()).nl();
|
||||
out.p(" Disk Path: ").p(vdisk_file.cpp_str()).nl();
|
||||
out.p(" Data Address: ").p(ostd::Utils::getHexStr(addr, true, 4).cpp_str()).nl();
|
||||
out.p(" Size: ").p(code.size()).reset().nl();
|
||||
}
|
||||
//Unknown
|
||||
else
|
||||
{
|
||||
out.fg("red").p("Error: Unknown tool.").reset().nl();
|
||||
return ErrorTopLevelUnknownTool;
|
||||
}
|
||||
return ErrorNoError;
|
||||
return dragon::Tools::execute(argc, argv);
|
||||
}
|
||||
Loading…
Reference in a new issue