[0.2.1577] - Added Virtual Display (Text-Single-Color mode only)

This commit is contained in:
OmniaX 2024-01-12 16:58:28 +01:00
parent 42f25f4e0b
commit cdd8afb05d
39 changed files with 914 additions and 227 deletions

View file

@ -31,12 +31,14 @@ list(APPEND RUNTIME_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/gui/Window.cpp
${CMAKE_CURRENT_LIST_DIR}/src/gui/RawTextRenderer.cpp
${CMAKE_CURRENT_LIST_DIR}/src/gui/Renderer.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualCPU.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualRAM.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/MemoryMapper.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualIODevices.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualHardDrive.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualDisplay.cpp
${CMAKE_CURRENT_LIST_DIR}/src/tools/Utils.cpp
)
@ -47,12 +49,14 @@ list(APPEND DEBUGGER_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/gui/Window.cpp
${CMAKE_CURRENT_LIST_DIR}/src/gui/RawTextRenderer.cpp
${CMAKE_CURRENT_LIST_DIR}/src/gui/Renderer.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualCPU.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualRAM.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/MemoryMapper.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualIODevices.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualHardDrive.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualDisplay.cpp
${CMAKE_CURRENT_LIST_DIR}/src/runtime/DragonRuntime.cpp
${CMAKE_CURRENT_LIST_DIR}/src/runtime/ConfigLoader.cpp

View file

@ -1 +1 @@
1576
1578

14
count_lines.sh Normal file
View file

@ -0,0 +1,14 @@
#!/bin/bash
green='\033[0;32m'
red='\033[0;31m'
clear='\033[0m'
printf "Counting lines of code...\n"
(find ./src/ -type f \( -iname \*.hpp -o -iname \*.cpp \) | xargs -n1 cpp -fpreprocessed -P | awk '!/^[{[:space:]}]*$/' | wc -l) > _lines.tmp 2> /dev/null
typeset -i netto_lines=$(cat _lines.tmp)
rm _lines.tmp
total_lines=$(find ./src/ -type f \( -iname \*.hpp -o -iname \*.cpp \) | xargs wc -l | sort -n | tail -1 | tr -d -c 0-9)
printf "Total: ${red}${total_lines}\n${clear}"
printf "Netto: ${green}${netto_lines}${clear} (No braces, comments or empty lines.)\n"

View file

@ -7,7 +7,7 @@ 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 --verbose
./dasm dss/bios/bios.dss -o dragon/bios.bin --save-disassembly disassembly/bios.dds --verbose
printf "\n${green}Creating Virtual Disk...\n${clear}"
rm dragon/disk1.dr
@ -19,8 +19,10 @@ printf "\n${green}Compiling MBR Block...\n${clear}"
printf "\n${green}Loading MBR Block...\n${clear}"
./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 --verbose
printf "${green}Compiling Test Program 1...\n"
./dasm dss/test1.dss -o test1.bin --save-disassembly disassembly/test1.dds --verbose
printf "${green}Compiling Test Program 2...\n"
./dasm dss/test2.dss -o test2.bin --save-disassembly disassembly/test2.dds --verbose
printf "${green}Creating Windows Release...\n"
cd ..
@ -31,17 +33,23 @@ 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 -r ./bin/config ./win-release
cp -r ./bin/disassembly/bios.dds ./win-release/disassembly
cp -r ./bin/disassembly/mbr.dds ./win-release/disassembly
cp -r ./bin/disassembly/test1.dds ./win-release/disassembly
cp -r ./bin/disassembly/test2.dds ./win-release/disassembly
cp -r ./bin/dragon ./win-release
rm ./bin/disassembly/test1.dds
rm ./bin/disassembly/test2.dds
mkdir ./win-release/dss
cp ./bin/dss/bios.dss ./win-release/dss
mkdir ./win-release/dss/bios
cp ./bin/dss/bios/bios.dss ./win-release/dss/bios
cp ./bin/dss/mbr.dss ./win-release/dss
cp ./bin/dss/test.dss ./win-release/dss
cp ./bin/dss/test1.dss ./win-release/dss
cp ./bin/dss/test2.dss ./win-release/dss
cp C:/msys64/ucrt64/bin/libgcc_s_seh-1.dll ./win-release
cp C:/msys64/ucrt64/bin/libstdc++-6.dll ./win-release
@ -49,4 +57,5 @@ cp C:/msys64/ucrt64/bin/libwinpthread-1.dll ./win-release
cp C:/msys64/ucrt64/bin/SDL2.dll ./win-release
cp C:/msys64/ucrt64/bin/libostd.dll ./win-release
cp ./run-test.bat ./win-release
cp ./extra/scripts/run-test-1.bat ./win-release
cp ./extra/scripts/run-test-2.bat ./win-release

View file

@ -1,3 +1,5 @@
Disks = dragon/disk1.dr
Bios = dragon/bios.bin
CMOS = dragon/cmos.dr
SingleColor_foreground = #009900FF
SingleColor_background = #111111FF

View file

@ -0,0 +1,122 @@
#==========================================================================================================================================
# Memory Map
#==========================================================================================================================================
0x0000 BIOS (4096 Bytes)
0x0FFF
-------
0x1000 CMOS (128 Bytes)
BootDisk: 0x0010
0x107F
-------
0x1080 INTERRUPT VECTOR (512 Bytes)
Status: 1 Byte
0xFF: Enabled
0x00: Disabled
Handler Address: 2 Byte
...Repeat...
0x127F
-------
0x1280 KEYBOARD MAPPING (224 Bytes)
0x135F
-------
0x1360 MOUSE MAPPING (32 Bytes)
0x137F
-------
0x1380 BOOTLOADER (512 Bytes)
0x157F
-------
0x1580 DISK INTERFACE (128 Bytes)
Read/Write:
Signal: 1 Byte
0x00: Start Operation
0x01: Cancel Current Operation
0xFF: Ignore
Mode: 1 Byte
0x00: Read
0x01: Write
Disk: 1 Byte
Sector: 2 Bytes
Address: 2 Bytes
DataSize: 2 Bytes
DataAddress: 2 Byte
ReadOnly:
Status: 1 Byte
0x00: Free
0x01: Writing
0x02: Reading
CurrentDisk: 1 Byte
CurrentSector: 2 Bytes
CurrentAddress: 2 Bytes
RestDataSize: 2 Bytes
SourceData: 2 Bytes
Free: 107 Byte
0x15FF
-------
0x1600 VIDEO CARD INTERFACE (256 Bytes)
0x00: Video Mode (1 Byte)
0x00: Text Single Color
# 0x01: Text 16-color
# 0x02: Text 256-color
# 0x03: Text True Color Mode
# 0x04: GFX Single Color
# 0x05: GFX 16-color
# 0x06: GFX 256-color
# 0x07: GFX True Color Mode
# 0x01: Clear Color (1 Byte)
# 0x02: Palette (1 Byte)
0x03: Signal (1 Byte)
0x00: Continue
0x02: Text Single Color - Direct Print Character
0x03: Text Single Color - Store character in buffer
0x04: Text SIngle Color - Direct Print buffer & Flush Buffer
0x05: Text Single Color - Flush Buffer
0x06: Text Single Color - Print Buffer Without Flushing
0xE0: Refresh Screen
0xE1: Clear Screen
0x04: Text Single Color Character
0x16FF
-------
0x1700 GENERIC SERIAL INTERFACE (64 Bytes)
0x173F
-------
0x1740 RAM (59583 Bytes)
0xFFFF
#==========================================================================================================================================
# INTERRUPTS
#==========================================================================================================================================
BIOS Specific - Software Interrupts:
====================================
0x20: BIOS Interrupt (Uses R10 register for specific functionality)
0x00: Set Interrupt Handler
0x01: Clear Interrupt Handler
0x10: Disk Interface
0x30: BIOS Video Interrupt (Uses R10 register for specific functionality)
0x01: Print Char in Text Single Mode (char stored in R9 register)
0x02: New Line in Text Single Mode
0x03: Print Null-Terminated String in Text Single Mode (string address stored in R9 register)
0x04: Print Integer in Text Single Mode (integer stored in R9 register)
0x05: Store Integer in buffer in Text Single Mode (integer stored in R9 register)
0x06: Store character in buffer in Text Single Mode (integer stored in R9 register)
0x07: Print buffer no flush in Text Single Mode
0x08: Print buffer and flush in Text Single Mode
0x09: Flush buffer in Text Single Mode
0x0A: Store Null-Terminated String in buffer in Text Single Mode (string address stored in R9 register)
0xE0: Refresh Screen
0xE1: Clear Screen
Machine Specific - Hardware Interrupts:
=======================================
0x80: Disk Interface Finished

View file

@ -1,69 +0,0 @@
0x0000 BIOS (4096 Bytes)
0x0FFF
-------
0x1000 CMOS (128 Bytes)
BootDisk: 0x0010
0x107F
-------
0x1080 INTERRUPT VECTOR (512 Bytes)
Status: 1 Byte
0xFF: Enabled
0x00: Disabled
Handler Address: 2 Byte
...Repeat...
0x127F
-------
0x1280 KEYBOARD MAPPING (224 Bytes)
0x135F
-------
0x1360 MOUSE MAPPING (32 Bytes)
0x137F
-------
0x1380 BOOTLOADER (512 Bytes)
0x157F
-------
0x1580 DISK INTERFACE (128 Bytes)
Read/Write:
Signal: 1 Byte
0x00: Start Operation
0x01: Cancel Current Operation
0xFF: Ignore
Mode: 1 Byte
0x00: Read
0x01: Write
Disk: 1 Byte
Sector: 2 Bytes
Address: 2 Bytes
DataSize: 2 Bytes
DataAddress: 2 Byte
ReadOnly:
Status: 1 Byte
0x00: Free
0x01: Writing
0x02: Reading
CurrentDisk: 1 Byte
CurrentSector: 2 Bytes
CurrentAddress: 2 Bytes
RestDataSize: 2 Bytes
SourceData: 2 Bytes
Free: 107 Byte
0x15FF
-------
0x1600 VIDEO CARD INTERFACE (256 Bytes)
0x00: Video Mode (1 Byte)
0x00: Single Color
0x01: 16-color
0x02: 256-color
0x03: True Color Mode
0x01: Clear Color (1 Byte)
0x02: Palette (1 Byte)
0x03: Signal (1 Byte)
0x00: Continue
0x01: Clear Screen
0x16FF
-------
0x1700 GENERIC SERIAL INTERFACE (64 Bytes)
0x173F
-------
0x1740 RAM (59583 Bytes)
0xFFFF

View file

@ -1,13 +0,0 @@
Software Interrupts:
====================
0x20: BIOS Interrupt (Uses R10 register for specific functionality)
0x00: Set Interrupt Handler
0x01: Clear Interrupt Handler
0x10: Disk Interface
0x30: BIOS Video Interrupt (Uses R10 register for specific functionality)
0x00: Clear Screen
Hardware Interrupts:
====================
0x80: Disk Interface Finished

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

View file

@ -5,21 +5,51 @@
DISK_INTERFACE 0x1580
RAM 0x1740
CMOS 0x1000
VGA 0x1600
@end
@group CMOS_Settings
BOOT_DISK {MemoryAddresses.CMOS + 0x0010}
BOOT_DISK { MemoryAddresses.CMOS + 0x0010 }
@end
@group VGA_Registers
VIDEO_MODE { MemoryAddresses.VGA + 0x0000 }
SIGNAL { MemoryAddresses.VGA + 0x0003 }
TEXT_SINGLE_CHAR { MemoryAddresses.VGA + 0x0004 }
BUFF_START { MemoryAddresses.VGA + 0x00E0 }
@end
@group VGA_VideoModes
TEXT_SINGLE_COLOR 0x00
@end
@group Sig_VGA_Text_Single_Color
CONTINUE 0x00
PRINT_CHAR 0x02
STORE_CHAR 0x03
PRINT_FLUSH_BUFF 0x04
FLUSH_BUFF 0x05
PRINT_BUFF 0x06
REFRESH_SCREEN 0xE0
CLEAR_SCREEN 0xE1
@end
@define S_REG_1 0x07
@define S_REG_2 0x08
@define S_REG_3 0x09
## ===============================================================================================
.load 0x0000 ## BIOS is mapped to address 0x0000 in memory
.data
$bios_version_number 0x00, 0x01 ## BIOS Version stored in memory
$_bios_name "DragonBIOS"
$_bios_version_number_maj 0x00, 0x00
$_bios_version_number_min 0x00, 0x03
## ============================= BIOS Program =============================
.code
## mov FL, 0
## jmp 0x1740
movb [VGA_Registers.VIDEO_MODE], VGA_VideoModes.TEXT_SINGLE_COLOR ## Enable Text_Single_Color graphics mode
mov FL, 0b0000000000000001 ## Zero the FL Register and enable interrupts
movb [{MemoryAddresses.INT_VEC + (0x20 * 3)}], 0xFF ## Setting up int 0x20 handler
mov [{MemoryAddresses.INT_VEC + (0x20 * 3) + 1}], $_int_20_handler ## --
@ -29,12 +59,30 @@
mov R8, 0x30 ## -Passing the interrupt's code to setup
int 0x20 ## -Calling int 0x20 with 0x00 as parameter, to set new handler up
## MBR Loading
mov R10, 0x03
mov R9, $_bios_name
int 0x30
mov R10, 0x01
mov R9, 32
int 0x30
mov R10, 0x04
mov R9, [$_bios_version_number_maj]
int 0x30
mov R10, 0x01
mov R9, 46
int 0x30
mov R10, 0x04
mov R9, [$_bios_version_number_min]
int 0x30
mov R10, 0x02
int 0x30
## MBR Loading //TODO: Figure out why and is not working
and FL, 0b1111111111111110 ## Disable interrupts
push 0
call $_load_mbr_data_block
or FL, 0b0000000000000001 ## Enable interrupts
## ----
## ---- //TODO: Figure out why or is not working
jmp MemoryAddresses.MBR ## Jump to start of MBR in memory
hlt ## Just in case somehow execution reaches this point
@ -84,10 +132,78 @@ _int_20_end:
## ========================== BIOS Video Interrupt handler =========================
_int_30_handler:
mov ACC, R10
jeq $_int_30_clear_screen, 0x0000
jeq $_int_30_direct_print_char_text_single, 0x0001
jeq $_int_30_direct_new_line_text_single, 0x0002
jeq $_int_30_direct_print_string_text_single, 0x0003
jeq $_int_30_direct_print_integer_text_single, 0x0004
jeq $_int_30_store_integer_text_single, 0x0005
jeq $_int_30_store_char_text_single, 0x0006
jeq $_int_30_print_buffer_no_flush_text_single, 0x0007
jeq $_int_30_print_buffer_and_flush_text_single, 0x0008
jeq $_int_30_flush_buffer_text_single, 0x0009
jeq $_int_30_store_string_text_single, 0x000A
jeq $_int_30_clear_screen, 0x00E0
jeq $_int_30_refresh_screen, 0x00E1
jmp $_int_30_end
_int_30_direct_print_char_text_single:
movb [VGA_Registers.TEXT_SINGLE_CHAR], R9
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.PRINT_CHAR
jmp $_int_30_end
_int_30_direct_new_line_text_single:
movb [VGA_Registers.TEXT_SINGLE_CHAR], 10 ## New line char code
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.STORE_CHAR
jmp $_int_30_end
_int_30_direct_print_string_text_single:
movb R1, *R9
movb [VGA_Registers.TEXT_SINGLE_CHAR], R1
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.PRINT_CHAR
inc R9
movb ACC, *R9
jne $_int_30_direct_print_string_text_single, 0
jmp $_int_30_end
_int_30_direct_print_integer_text_single:
mov reg(S_REG_1), Sig_VGA_Text_Single_Color.PRINT_CHAR
push R9
push 1
call $_print_integer
jmp $_int_30_end
_int_30_store_integer_text_single:
mov reg(S_REG_1), Sig_VGA_Text_Single_Color.STORE_CHAR
push R9
push 1
call $_print_integer
jmp $_int_30_end
_int_30_store_char_text_single:
movb [VGA_Registers.TEXT_SINGLE_CHAR], R9
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.STORE_CHAR
jmp $_int_30_end
_int_30_print_buffer_no_flush_text_single:
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.PRINT_BUFF
_int_30_print_buffer_and_flush_text_single:
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.PRINT_FLUSH_BUFF
jmp $_int_30_end
_int_30_flush_buffer_text_single:
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.FLUSH_BUFF
jmp $_int_30_end
_int_30_store_string_text_single:
movb R1, *R9
movb [VGA_Registers.TEXT_SINGLE_CHAR], R1
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.STORE_CHAR
inc R9
movb ACC, *R9
jne $_int_30_store_string_text_single, 0
debug_break
jmp $_int_30_end
_int_30_clear_screen:
nop
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.CLEAR_SCREEN
jmp $_int_30_end
_int_30_refresh_screen:
movb [VGA_Registers.SIGNAL], Sig_VGA_Text_Single_Color.REFRESH_SCREEN
jmp $_int_30_end
_int_30_end:
rti
## ==================================================================================
@ -132,4 +248,44 @@ _set_interrupt_vector_entry_end:
mov *R1, ACC
ret
_print_integer:
mov R1, 0
arg ACC
jne $_print_integer_loop, 0
push 48 ## '0' ASCII is 48
inc R1
jmp $_print_integer_loop_end
_print_integer_loop:
jeq $_print_integer_loop_end, 0
div ACC, 10
mov R2, ACC
add RV, 48 ## '0' ASCII is 48
push ACC
inc R1
mov ACC, R2
jmp $_print_integer_loop
_print_integer_loop_end:
pop R9
dec R1
movb [VGA_Registers.TEXT_SINGLE_CHAR], R9
movb [VGA_Registers.SIGNAL], reg(S_REG_1)
mov ACC, R1
jne $_print_integer_loop_end, 0
ret
_strlen:
arg R1
mov R2, 0
_strlen_loop:
movb ACC, *R1
inc R1
jeq $_strlen_loop_end, 0
inc R2
jmp $_strlen_loop
_strlen_loop_end:
mov RV, R2
ret
.fixed 4096, 0x00 ## BIOS Needs to be 4096 Bytes exactly

View file

@ -1,80 +1,48 @@
.load 0x1740
##=================================================================================================================================
## This is the test2 program for the Dragon Virtual Machine. This example simply demonstrates the Virtual Display in Text-Single-Color
## mode, by printing an increasing counter followed by whatever is in the $string variable. The program also clears the screen
## every 10 lines.
##=================================================================================================================================
@struct Rectangle
width:2 > 0x11, 0x22
height:2 > 0x99
x:2
y:2 > 0xAA
@end
.load 0x1740
.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
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 $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
mov R1, 99 ## Zero the counter
infinite_loop:
inc R1 ## Increment the counter
div R1, 10 ## Divide the counter by 10
mov ACC, RV
jne $no_clear_screen, 0 ## If reminder not zero, keep going
mov R10, 0xE0 ## Else clear the screen (0x0E is for 'Clear Screen' functionality in int 0x30)
int 0x30 ## BIOS Video Interrupt
no_clear_screen:
## Print counter
mov R9, R1 ## Pass the counter as parameter to int 0x30
mov R10, 0x05 ## 0x05 is for 'Store Integer in buffer' functionality in int 0x30
int 0x30 ## BIOS Video Interrupt
## Print a space
mov R9, 32 ## Pass 32 (space character in ASCII) as parameter to int 0x30
mov R10, 0x06 ## 0x06 is for 'Store Character in buffer' functionality in int 0x30
int 0x30 ## BIOS Video Interrupt
## Print the string
mov R9, $string ## Pass the address of the string as parameter to int 0x30
mov R10, 0x0A ## 0x0A is for 'Store String in buffer' functionality in int 0x30
int 0x30 ## BIOS Video Interrupt
## Print a new-line character
mov R10, 0x02 ## 0x02 is for 'Print New-Line' functionality in int 0x30
## Printing a new line when in Text-Single-Color Mode also
## prints and flushes the buffer
int 0x30 ## BIOS Video Interrupt
jmp $infinite_loop ## jump to the beginning of infinite loop
hlt
testinttest:
push 0
call $inttest
ret
inttest:
push 0
call $testint
ret
testint:
push 0
call $test_int
ret
test_int:
push 0
call $int_test
ret
int_test:
nop
ret
strlen:
arg R1
mov R2, 0
loop:
movb ACC, *R1
inc R1
jeq $loop_end, 0
not_zero:
inc R2
jmp $loop
loop_end:
mov RV, R2
ret
.fixed 512, 0x00

View file

@ -1,5 +1,5 @@
##=================================================================================================================================
## This is the test program for the Dragon Virtual Machine. The example has two subroutines: One is the $strlen subroutine,
## This is the test1 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

48
extra/dss/test2.dss Normal file
View file

@ -0,0 +1,48 @@
##=================================================================================================================================
## This is the test2 program for the Dragon Virtual Machine. This example simply demonstrates the Virtual Display in Text-Single-Color
## mode, by printing an increasing counter followed by whatever is in the $string variable. The program also clears the screen
## every 10 lines.
##=================================================================================================================================
.load 0x1740
.data
$string "Hello World!!"
.code
mov R1, 99 ## Zero the counter
infinite_loop:
inc R1 ## Increment the counter
div R1, 10 ## Divide the counter by 10
mov ACC, RV
jne $no_clear_screen, 0 ## If reminder not zero, keep going
mov R10, 0xE0 ## Else clear the screen (0x0E is for 'Clear Screen' functionality in int 0x30)
int 0x30 ## BIOS Video Interrupt
no_clear_screen:
## Print counter
mov R9, R1 ## Pass the counter as parameter to int 0x30
mov R10, 0x05 ## 0x05 is for 'Store Integer in buffer' functionality in int 0x30
int 0x30 ## BIOS Video Interrupt
## Print a space
mov R9, 32 ## Pass 32 (space character in ASCII) as parameter to int 0x30
mov R10, 0x06 ## 0x06 is for 'Store Character in buffer' functionality in int 0x30
int 0x30 ## BIOS Video Interrupt
## Print the string
mov R9, $string ## Pass the address of the string as parameter to int 0x30
mov R10, 0x0A ## 0x0A is for 'Store String in buffer' functionality in int 0x30
int 0x30 ## BIOS Video Interrupt
## Print a new-line character
mov R10, 0x02 ## 0x02 is for 'Print New-Line' functionality in int 0x30
## Printing a new line when in Text-Single-Color Mode also
## prints and flushes the buffer
int 0x30 ## BIOS Video Interrupt
jmp $infinite_loop ## jump to the beginning of infinite loop
hlt
.fixed 512, 0x00

BIN
extra/font_big.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 KiB

13
extra/make Normal file
View file

@ -0,0 +1,13 @@
#!/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
make
elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
mingw32-make.exe
fi
printf "${green}\n=================================================================================================================\n\n"

25
extra/make_and_debug Normal file
View file

@ -0,0 +1,25 @@
#!/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
make
elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
mingw32-make.exe
fi
printf "${green}\n=================================================================================================================\n\n"
if [ $? -eq 0 ]; then
cd scripts
/bin/bash ./bios_flash
/bin/bash ./load_mbr
cd ..
printf "${green}Compiling Test Program...\n"
./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
cp dragon/disk1.dr ../extra/dragon/disk1.dr
cp dragon/cmos.dr ../extra/dragon/cmos.dr
fi

View file

@ -19,8 +19,7 @@ if [ $? -eq 0 ]; then
printf "${green}Compiling Test Program...\n"
./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
./dvm config/testMachine.dvm --force-load newTest.bin 0x00
cp dragon/disk1.dr ../extra/dragon/disk1.dr
cp dragon/cmos.dr ../extra/dragon/cmos.dr
fi

View file

@ -5,6 +5,6 @@ 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 --verbose
cp ../extra/dss/bios/bios.dss ./dss/bios/bios.dss
./dasm dss/bios/bios.dss -o dragon/bios.bin --save-disassembly disassembly/bios.dds --verbose
cp dragon/bios.bin ../extra/dragon/bios.bin

View file

@ -0,0 +1,2 @@
dasm dss/test1.dss -o test1.bin --save-disassembly disassembly/test1.dds --verbose
ddb config/testMachine.dvm --force-load test1.bin 0x00 --verbose-load --hide-vdisplay

View file

@ -0,0 +1,2 @@
dasm dss/test2.dss -o test2.bin --save-disassembly disassembly/test2.dds --verbose
ddb config/testMachine.dvm --force-load test2.bin 0x00 --verbose-load --hide-vdisplay

View file

@ -1,2 +0,0 @@
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

View file

@ -128,7 +128,7 @@ namespace dragon
void Assembler::loadSource(ostd::String source)
{
m_rawSource = source;
m_lines = ostd::String(source).tokenize("\n").getRawData();
m_lines = ostd::String(source.replaceAll("\t", " ")).tokenize("\n").getRawData();
}
ostd::ByteStream Assembler::assembleToFile(ostd::String sourceFileName, ostd::String binaryFileName)
@ -245,7 +245,7 @@ namespace dragon
{
ostd::String lineEdit(line);
for (int32_t i = defines.size() - 1; i >= 0; i--)
lineEdit.replaceAll(defines[i].name, defines[i].value);
lineEdit.replaceAll(defines[i].name, defines[i].value.new_trim());
line = lineEdit;
}
m_lines.clear();
@ -1190,7 +1190,7 @@ namespace dragon
}
return;
}
else if (instEdit == "add" || instEdit == "sub" || instEdit == "mul")
else if (instEdit == "add" || instEdit == "sub" || instEdit == "mul" || instEdit == "div")
{
m_code.push_back(0x00);
eOperandType opType = parseOperand(st.next(), word);
@ -1208,6 +1208,7 @@ namespace dragon
if (instEdit == "add") m_code[m_code.size() - 2] = data::OpCodes::AddImmReg;
else if (instEdit == "sub") m_code[m_code.size() - 2] = data::OpCodes::SubImmReg;
else if (instEdit == "mul") m_code[m_code.size() - 2] = data::OpCodes::MulImmReg;
else if (instEdit == "div") m_code[m_code.size() - 2] = data::OpCodes::DivImmReg;
m_code.push_back((uint8_t)((word & 0xFF00) >> 8));
m_code.push_back((uint8_t)(word & 0x00FF));
}
@ -1216,6 +1217,7 @@ namespace dragon
if (instEdit == "add") m_code[m_code.size() - 2] = data::OpCodes::AddRegReg;
else if (instEdit == "sub") m_code[m_code.size() - 2] = data::OpCodes::SubRegReg;
else if (instEdit == "mul") m_code[m_code.size() - 2] = data::OpCodes::MulRegReg;
else if (instEdit == "div") m_code[m_code.size() - 2] = data::OpCodes::DivRegReg;
m_code.push_back((uint8_t)word);
}
else
@ -1435,6 +1437,26 @@ namespace dragon
return eOperandType::DerefRegister;
return eOperandType::Register;
}
else if (opEdit.startsWith("reg(") && opEdit.endsWith(")"))
{
opEdit.substr(4, opEdit.len() - 1);
opEdit.trim();
if (!opEdit.isNumeric())
{
std::cout << "Invalid numeric value: " << opEdit << "\n";
return eOperandType::Error;
}
uint8_t _reg = opEdit.toInt();
if (_reg >= data::Registers::Last)
{
std::cout << "Invalid Register: " << opEdit << "\n";
return eOperandType::Error;
}
outOp = (int16_t)_reg;
if (derefReg)
return eOperandType::DerefRegister;
return eOperandType::Register;
}
if (derefReg)
{
std::cout << "Invalid Register Dereferencing: " << op << "\n";

View file

@ -13,12 +13,12 @@ namespace dragon
{
validate();
enableSignals();
connectSignal(dragon::Window::Signal_OnWindowClosed);
connectSignal(ostd::tBuiltinSignals::WindowClosed);
}
void Debugger::tCloseEventListener::handleSignal(ostd::tSignal& signal)
{
m_mainWindowClosed = signal.ID == dragon::Window::Signal_OnWindowClosed;
m_mainWindowClosed = signal.ID == ostd::tBuiltinSignals::WindowClosed;
}
@ -1290,6 +1290,11 @@ namespace dragon
data().args.step_exec = !data().args.step_exec;
output().p("Step execution = ").p(STR_BOOL(data().args.step_exec)).nl();
}
else if (data().command == "display")
{
data().args.hide_virtual_display = !data().args.hide_virtual_display;
output().p("Virtual Display Hidden = ").p(STR_BOOL(data().args.hide_virtual_display)).nl();
}
}
}
@ -1526,6 +1531,9 @@ namespace dragon
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();
tmpCommand = "display";
tmpCommand.addRightPadding(commandLength);
out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to enable/disable the Virtual Display for the runtime.").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();

View file

@ -19,7 +19,7 @@ namespace dragon
bool step_exec = false;
bool track_step_diff = true;
bool auto_start_debug = false;
bool hide_virtual_display = false;
bool hide_virtual_display = true;
bool track_call_stack = true;
bool auto_track_all_data_symbols = true;
ostd::String force_load_file = "";

70
src/gui/Renderer.cpp Normal file
View file

@ -0,0 +1,70 @@
#include "Renderer.hpp"
#include "Window.hpp"
#include <ostd/Utils.hpp>
namespace dragon
{
Renderer::~Renderer(void)
{
if (isInvalid()) return;
ostd::Utils::destroyArray(m_pixels);
SDL_DestroyTexture(m_texture);
}
void Renderer::initialize(Window& parent)
{
if (isValid()) return; //TODO: Error
if (!parent.isValid() || !parent.isInitialized())
return; //TODO: Error
m_parent = &parent;
m_pixels = ostd::Utils::createArray<uint32_t>(parent.getWindowWidth() * parent.getWindowHeight());
m_texture = SDL_CreateTexture(parent.getSDLRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, parent.getWindowWidth(), parent.getWindowHeight());
m_windowWidth = parent.getWindowWidth();
m_windowHeight = parent.getWindowHeight();
setTypeName("lspp::gfx::Renderer");
enableSignals();
connectSignal(ostd::tBuiltinSignals::WindowResized);
validate();
}
void Renderer::handleSignal(ostd::tSignal& signal)
{
if (isInvalid()) return;
if (signal.ID == ostd::tBuiltinSignals::WindowResized)
{
m_pixels = ostd::Utils::resizeArray<uint32_t>(m_pixels, m_parent->getWindowWidth() * m_parent->getWindowHeight());
SDL_DestroyTexture(m_texture);
m_texture = SDL_CreateTexture(m_parent->getSDLRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, m_parent->getWindowWidth(), m_parent->getWindowHeight());
m_windowWidth = m_parent->getWindowWidth();
m_windowHeight = m_parent->getWindowHeight();
updateBuffer();
displayBuffer();
}
}
void Renderer::updateBuffer(void)
{
if (isInvalid()) return;
SDL_UpdateTexture(m_texture, NULL, m_pixels, m_windowWidth * 4);
}
void Renderer::displayBuffer(void)
{
if (isInvalid()) return;
SDL_Rect rect { 0, 0, m_windowWidth, m_windowHeight };
SDL_RenderCopy(m_parent->getSDLRenderer(), m_texture, NULL, &rect);
}
void Renderer::clear(const ostd::Color& color)
{
if (isInvalid()) return;
for (int32_t y = 0; y < m_windowHeight; y++)
{
for (uint32_t x = 0; x < m_windowWidth; x++)
{
int32_t index = CONVERT_2D_1D(x, y, m_windowWidth);
m_pixels[index] = color.asInteger();
}
}
}
}

29
src/gui/Renderer.hpp Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include <ostd/Color.hpp>
#include "../tools/SDLInclude.hpp"
namespace dragon
{
class Window;
class Renderer : public ostd::BaseObject
{
public:
inline Renderer(void) { invalidate(); }
~Renderer(void);
void initialize(Window& parent);
void handleSignal(ostd::tSignal& signal) override;
void updateBuffer(void);
void displayBuffer(void);
inline uint32_t* getScreenPixels(void) { return m_pixels; }
void clear(const ostd::Color& color);
private:
uint32_t* m_pixels { nullptr };
SDL_Texture* m_texture { nullptr };
Window* m_parent { nullptr };
int32_t m_windowWidth { 0 };
int32_t m_windowHeight { 0 };
};
}

View file

@ -54,8 +54,9 @@ namespace dragon
if (!m_initialized) return;
Uint64 start = SDL_GetPerformanceCounter();
handleEvents();
onUpdate();
if (m_refreshScreen)
SDL_RenderClear(m_renderer);
onUpdate();
onRender();
SDL_RenderPresent(m_renderer);
Uint64 end = SDL_GetPerformanceCounter();
@ -81,6 +82,7 @@ namespace dragon
{
if (!isInitialized()) return;
SDL_SetWindowSize(m_window, width, height);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::WindowResized, ostd::tSignalPriority::RealTime);
}
void Window::setTitle(const ostd::String& title)
@ -113,7 +115,7 @@ namespace dragon
if (event.type == SDL_QUIT)
{
m_running = false;
ostd::SignalHandler::emitSignal(Signal_OnWindowClosed, ostd::tSignalPriority::Normal, *this);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::WindowClosed, ostd::tSignalPriority::Normal, *this);
}
else if (event.type == SDL_WINDOWEVENT)
{
@ -129,7 +131,7 @@ namespace dragon
{
MouseEventData mmd = l_getMouseState();
if (isMouseDragEventEnabled() && mmd.button != MouseEventData::eButton::None)
ostd::SignalHandler::emitSignal(Signal_OnMouseDragged, ostd::tSignalPriority::RealTime, mmd);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::WindowClosed, ostd::tSignalPriority::RealTime, mmd);
else
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::MouseMoved, ostd::tSignalPriority::RealTime, mmd);
}

View file

@ -49,6 +49,8 @@ namespace dragon
SDL_Surface* m_fontSurface { nullptr };
uint32_t* m_fontPixels { nullptr };
bool m_refreshScreen { true };
private:
int32_t m_windowWidth { 0 };
int32_t m_windowHeight { 0 };
@ -61,11 +63,6 @@ namespace dragon
bool m_deagEventEnabled { false };
bool m_running { false };
bool m_initialized { false };
public:
//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);
};
class WindowResizedData : public ostd::BaseObject
{

View file

@ -413,6 +413,29 @@ namespace dragon
writeRegister(data::Registers::ACC, regValue1 * regValue2);
}
break;
case data::OpCodes::DivImmReg: //TODO: Division by zero is unhandled
{
uint8_t regAddr = fetch8();
int16_t literal = fetch16();
int16_t regValue = readRegister(regAddr);
int16_t quotient = regValue / literal;
int16_t reminder = regValue % literal;
writeRegister(data::Registers::ACC, quotient);
writeRegister(data::Registers::RV, reminder);
}
break;
case data::OpCodes::DivRegReg: //TODO: Division by zero is unhandled
{
uint8_t regAddr1 = fetch8();
uint8_t regAddr2 = fetch8();
int16_t regValue1 = readRegister(regAddr1);
int16_t regValue2 = readRegister(regAddr2);
int16_t quotient = regValue1 / regValue2;
int16_t reminder = regValue1 % regValue2;
writeRegister(data::Registers::ACC, quotient);
writeRegister(data::Registers::RV, reminder);
}
break;
case data::OpCodes::IncReg:
{
uint8_t regAddr = fetch8();

View file

@ -0,0 +1,158 @@
#include "VirtualDisplay.hpp"
#include "../gui/RawTextRenderer.hpp"
#include "../runtime/DragonRuntime.hpp"
namespace dragon
{
namespace hw
{
void VirtualDisplay::onInitialize(void)
{
m_renderer.initialize(*this);
RawTextRenderer::initialize();
}
void VirtualDisplay::onDestroy(void) { }
void VirtualDisplay::onRender(void)
{
auto& config = DragonRuntime::machine_config;
if (m_refreshScreen)
{
m_renderer.clear(config.singleColor_background);
for (int32_t i = 0; i < m_singleTextLines.size(); i++)
{
auto& line = m_singleTextLines[i];
RawTextRenderer::drawString(line, 0, i, m_renderer.getScreenPixels(), getWindowWidth(), getWindowHeight(), m_fontPixels, config.singleColor_foreground);
}
m_refreshScreen = false;
}
m_renderer.updateBuffer();
m_renderer.displayBuffer();
}
void VirtualDisplay::onUpdate(void)
{
auto& mem = DragonRuntime::memMap;
uint16_t vga_addr = data::MemoryMapAddresses::VideoCardInterface_Start;
uint8_t video_mode = mem.read8(vga_addr + tRegisters::VideoMode);
uint8_t signal = mem.read8(vga_addr + tRegisters::Signal);
if (signal == tSignalValues::Continue) return;
if (video_mode == tVideoModeValues::TextSingleColor)
{
if (signal == tSignalValues::TextSingleColor_DirectPrintChar)
{
char c = (char)mem.read8(vga_addr + tRegisters::TextSingleCharacter);
single_text_add_char_to_line(c);
}
else if (signal == tSignalValues::TextSingleColor_StoreChar)
{
char c = (char)mem.read8(vga_addr + tRegisters::TextSingleCharacter);
single_text_add_char_to_buffer(c);
}
else if (signal == tSignalValues::TextSingleColor_DirectPrintBuffNoFlush)
{
single_text_print_buffer_no_flush();
}
else if (signal == tSignalValues::TextSingleColor_DirectPrintBuffAndFlush)
{
single_text_print_buffer_and_flush();
}
else if (signal == tSignalValues::TextSingleColor_FlushBuffer)
{
single_text_flush_buffer();
}
else if (signal == tSignalValues::ClearSCreen)
{
single_text_clear_screen();
}
else if (signal == tSignalValues::RefreshScreen)
{
single_text_refresh_screen();
}
}
else return;
mem.write8(vga_addr + tRegisters::Signal, tSignalValues::Continue);
}
void VirtualDisplay::onFixedUpdate(void) { }
void VirtualDisplay::onSlowUpdate(void) { }
void VirtualDisplay::single_text_add_char_to_line(char c)
{
auto& config = DragonRuntime::machine_config;
if (m_singleTextLines.size() == 0)
{
m_singleTextLines.push_back(ostd::String().addChar(c));
RawTextRenderer::drawString(ostd::String().addChar(c), 0, 0, m_renderer.getScreenPixels(), getWindowWidth(), getWindowHeight(), m_fontPixels, config.singleColor_foreground);
return;
}
auto& line = m_singleTextLines[m_singleTextLines.size() - 1];
if (c == '\n')
m_singleTextLines.push_back("");
else if (isprint(c))
{
if (line.len() == RawTextRenderer::CONSOLE_CHARS_H)
{
m_singleTextLines.push_back(ostd::String().addChar(c));
auto& line = m_singleTextLines[m_singleTextLines.size() - 1];
RawTextRenderer::drawString(ostd::String().addChar(c), line.len() - 1, m_singleTextLines.size() - 1, m_renderer.getScreenPixels(), getWindowWidth(), getWindowHeight(), m_fontPixels, config.singleColor_foreground);
}
else
{
line.addChar(c);
RawTextRenderer::drawString(ostd::String().addChar(c), line.len() - 1, m_singleTextLines.size() - 1, m_renderer.getScreenPixels(), getWindowWidth(), getWindowHeight(), m_fontPixels, config.singleColor_foreground);
}
}
else return;
if (m_singleTextLines.size() == RawTextRenderer::CONSOLE_CHARS_V + 1)
{
m_refreshScreen = true;
m_singleTextLines.erase(m_singleTextLines.begin());
}
}
void VirtualDisplay::single_text_add_char_to_buffer(char c)
{
if (c == '\n' || m_singleTextBuffer.len() == RawTextRenderer::CONSOLE_CHARS_H)
{
single_text_print_buffer_and_flush();
single_text_add_char_to_line(c);
}
else
m_singleTextBuffer.addChar(c);
}
void VirtualDisplay::single_text_flush_buffer(void)
{
m_singleTextBuffer = "";
}
void VirtualDisplay::single_text_print_buffer_and_flush(void)
{
for (auto& ch : m_singleTextBuffer)
single_text_add_char_to_line(ch);
single_text_flush_buffer();
}
void VirtualDisplay::single_text_print_buffer_no_flush(void)
{
for (auto& ch : m_singleTextBuffer)
single_text_add_char_to_line(ch);
}
void VirtualDisplay::single_text_clear_screen(void)
{
m_singleTextLines.clear();
m_refreshScreen = true;
}
void VirtualDisplay::single_text_refresh_screen(void)
{
m_refreshScreen = true;
}
}
}

View file

@ -0,0 +1,60 @@
#pragma once
#include "../gui/Window.hpp"
#include "../gui/Renderer.hpp"
namespace dragon
{
namespace hw
{
class VirtualDisplay : public Window
{
public: struct tRegisters
{
inline static constexpr uint8_t VideoMode = 0x00;
inline static constexpr uint8_t Signal = 0x03;
inline static constexpr uint8_t TextSingleCharacter = 0x04;
};
public: struct tVideoModeValues
{
inline static constexpr uint8_t TextSingleColor = 0x00;
};
public: struct tSignalValues
{
inline static constexpr uint8_t Continue = 0x00;
inline static constexpr uint8_t TextSingleColor_DirectPrintChar = 0x02;
inline static constexpr uint8_t TextSingleColor_StoreChar = 0x03;
inline static constexpr uint8_t TextSingleColor_DirectPrintBuffAndFlush = 0x04;
inline static constexpr uint8_t TextSingleColor_FlushBuffer = 0x05;
inline static constexpr uint8_t TextSingleColor_DirectPrintBuffNoFlush = 0x06;
inline static constexpr uint8_t RefreshScreen = 0xE0;
inline static constexpr uint8_t ClearSCreen = 0xE1;
};
public:
void onInitialize(void) override;
void onDestroy(void) override;
void onRender(void) override;
void onUpdate(void) override;
void onFixedUpdate(void) override;
void onSlowUpdate(void) override;
private:
void single_text_add_char_to_line(char c);
void single_text_add_char_to_buffer(char c);
void single_text_flush_buffer(void);
void single_text_print_buffer_and_flush(void);
void single_text_print_buffer_no_flush(void);
void single_text_clear_screen(void);
void single_text_refresh_screen(void);
private:
Renderer m_renderer;
std::vector<ostd::String> m_singleTextLines;
ostd::String m_singleTextBuffer { "" };
};
}
}

View file

@ -438,31 +438,54 @@ namespace dragon
Graphics::Graphics(void)
{
m_videoMemory.init(0xFFFF);
}
int8_t Graphics::read8(uint16_t addr)
{
return 0x00;
int8_t outVal = 0;
if (!m_videoMemory.r_Byte(addr, outVal))
{
data::ErrorHandler::pushError(data::ErrorCodes::Graphics_MemoryReadFailed, "Failed to read byte from Graphics Memory");
return 0;
}
return outVal;
}
int16_t Graphics::read16(uint16_t addr)
{
return 0x0000;
int16_t outVal = 0;
if (!m_videoMemory.r_Word(addr, outVal))
{
data::ErrorHandler::pushError(data::ErrorCodes::Graphics_MemoryReadFailed, "Failed to read word from Graphics Memory");
return 0;
}
return outVal;
}
int8_t Graphics::write8(uint16_t addr, int8_t value)
{
return 0x00;
if (!m_videoMemory.w_Byte(addr, value))
{
data::ErrorHandler::pushError(data::ErrorCodes::Graphics_MemoryWriteFailed, "Failed to write byte to Graphics Memory");
return 0;
}
return value;
}
int16_t Graphics::write16(uint16_t addr, int16_t value)
{
return 0x0000;
if (!m_videoMemory.w_Word(addr, value))
{
data::ErrorHandler::pushError(data::ErrorCodes::Graphics_MemoryWriteFailed, "Failed to word byte to Graphics Memory");
return 0;
}
return value;
}
ostd::ByteStream* Graphics::getByteStream(void)
{
return nullptr;
return &m_videoMemory.getData();
}

View file

@ -170,6 +170,7 @@ namespace dragon
ostd::ByteStream* getByteStream(void) override;
private:
ostd::serial::SerialIO m_videoMemory;
};
class SerialPort : public IMemoryDevice
{

View file

@ -40,6 +40,16 @@ namespace dragon
lineEdit = tokens.next();
config.cmos_path = lineEdit;
}
else if (lineEdit == "singlecolor_foreground")
{
lineEdit = tokens.next();
config.singleColor_foreground.set(lineEdit);
}
else if (lineEdit == "singlecolor_background")
{
lineEdit = tokens.next();
config.singleColor_background.set(lineEdit);
}
else continue; //TODO: Warning
}
return validate_machine_config(config);

View file

@ -1,6 +1,6 @@
#pragma once
#include <ostd/String.hpp>
#include <ostd/Color.hpp>
#include <map>
namespace dragon
@ -10,6 +10,8 @@ namespace dragon
std::map<int32_t, ostd::String> vdisk_paths;
ostd::String bios_path;
ostd::String cmos_path;
ostd::Color singleColor_background;
ostd::Color singleColor_foreground;
inline bool isValid(void) const { return m_valid; }

View file

@ -136,10 +136,9 @@ namespace dragon
if (verbose)
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;
vDisplay.setSize(w, h);
vDisplay.initialize(w, h, "DragonVM", "font.bmp");
if (hideVirtualDisplay)
vDisplay.hide();
if (verbose)

View file

@ -7,6 +7,7 @@
#include "../hardware/VirtualRAM.hpp"
#include "../hardware/VirtualIODevices.hpp"
#include "../hardware/VirtualHardDrive.hpp"
#include "../hardware/VirtualDisplay.hpp"
#include "../tools/GlobalData.hpp"
@ -73,7 +74,7 @@ namespace dragon
std::vector<tCallInfo> callStack;
};
public:
static void printRegisters(dragon::hw::VirtualCPU& cpu);
static void printRegisters(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);
@ -99,24 +100,24 @@ namespace dragon
public:
inline static ostd::ConsoleOutputHandler out;
inline static dragon::hw::MemoryMapper memMap;
inline static dragon::hw::VirtualCPU cpu { memMap };
inline static dragon::hw::VirtualRAM ram;
inline static dragon::hw::InterruptVector intVec;
inline static dragon::hw::VirtualBIOS vBIOS;
inline static dragon::hw::interface::CMOS vCMOS;
inline static dragon::hw::VirtualBootloader vMBR;
inline static dragon::hw::VirtualKeyboard vKeyboard;
inline static dragon::hw::VirtualMouse vMouse;
inline static dragon::hw::interface::Disk vDiskInterface { memMap, cpu };
inline static dragon::hw::interface::Graphics vGraphicsInterface;
inline static dragon::hw::interface::SerialPort vSerialInterface;
inline static hw::MemoryMapper memMap;
inline static hw::VirtualCPU cpu { memMap };
inline static hw::VirtualRAM ram;
inline static hw::InterruptVector intVec;
inline static hw::VirtualBIOS vBIOS;
inline static hw::interface::CMOS vCMOS;
inline static hw::VirtualBootloader vMBR;
inline static hw::VirtualKeyboard vKeyboard;
inline static hw::VirtualMouse vMouse;
inline static hw::interface::Disk vDiskInterface { memMap, cpu };
inline static hw::interface::Graphics vGraphicsInterface;
inline static hw::interface::SerialPort vSerialInterface;
inline static std::unordered_map<int32_t, dragon::hw::VirtualHardDrive> vDisks;
inline static std::unordered_map<int32_t, hw::VirtualHardDrive> vDisks;
inline static dragon::Window vDisplay;
inline static hw::VirtualDisplay vDisplay;
inline static dragon::tMachineConfig machine_config;
inline static tMachineConfig machine_config;
private:
inline static tMachineDebugInfo s_machineInfo;

View file

@ -49,6 +49,9 @@ namespace dragon
inline static constexpr uint64_t IntVector_InvalidAddress = 0x7000000000000000;
inline static constexpr uint64_t Graphics_MemoryReadFailed = 0x8000000000000000;
inline static constexpr uint64_t Graphics_MemoryWriteFailed = 0x8000000000000001;
};
class ErrorHandler
@ -158,9 +161,7 @@ namespace dragon
inline static constexpr uint8_t PP = 0x04;
inline static constexpr uint8_t FL = 0x05;
inline static constexpr uint8_t ACC = 0x06;
//TODO: Either add general purpose registers in this space or check when read/write registers
//0x07, 0x08, 0x09 Are hidden registers used internally, but can be normally accessed by address
inline static constexpr uint8_t R1 = 0x0A;
inline static constexpr uint8_t R2 = 0x0B;
inline static constexpr uint8_t R3 = 0x0C;
@ -184,11 +185,6 @@ namespace dragon
class InterruptCodes
{
public:
inline static constexpr uint8_t Keyboard = 0x10;
inline static constexpr uint8_t Mouse = 0x11;
inline static constexpr uint8_t BiosInterrupt = 0x20;
inline static constexpr uint8_t BiosVideoInterrupt = 0x30;
inline static constexpr uint8_t DiskInterfaceFFinished = 0x80;
};
@ -229,6 +225,8 @@ namespace dragon
inline static constexpr uint8_t SubImmReg = 0x33;
inline static constexpr uint8_t MulRegReg = 0x34;
inline static constexpr uint8_t MulImmReg = 0x35;
inline static constexpr uint8_t DivRegReg = 0x36;
inline static constexpr uint8_t DivImmReg = 0x37;
inline static constexpr uint8_t IncReg = 0x40;
inline static constexpr uint8_t DecReg = 0x41;
@ -305,6 +303,8 @@ namespace dragon
case data::OpCodes::SubRegReg: return "SubRegReg";
case data::OpCodes::MulImmReg: return "MulImmReg";
case data::OpCodes::MulRegReg: return "MulRegReg";
case data::OpCodes::DivImmReg: return "DivImmReg";
case data::OpCodes::DivRegReg: return "DivRegReg";
case data::OpCodes::IncReg: return "IncReg";
case data::OpCodes::DecReg: return "DecReg";
case data::OpCodes::RShiftRegImm: return "RShiftRegImm";
@ -379,6 +379,8 @@ namespace dragon
case data::OpCodes::SubRegReg: return 3;
case data::OpCodes::MulImmReg: return 4;
case data::OpCodes::MulRegReg: return 3;
case data::OpCodes::DivImmReg: return 4;
case data::OpCodes::DivRegReg: return 3;
case data::OpCodes::IncReg: return 2;
case data::OpCodes::DecReg: return 2;
case data::OpCodes::RShiftRegImm: return 4;