[0.2.1583] - Added basic Keyboard Controller

This commit is contained in:
OmniaX 2024-01-26 11:31:29 +01:00
parent 713711d247
commit 9fdd690d0c
29 changed files with 1101 additions and 55 deletions

View file

@ -1,5 +1,5 @@
{
"C_Cpp.errorSquiggles": "Enabled",
"C_Cpp.errorSquiggles": "enabled",
"files.associations": {
"functional": "cpp",
"thread": "cpp",
@ -105,7 +105,7 @@
"tab.inactiveBackground": "#000",
"tab.activeBackground": "#1b1b1b",
"tab.activeBorder": "#bb5400",
"editorIndentGuide.background": "#252525",
"editorIndentGuide.background1": "#252525",
"editorWhitespace.foreground": "#683700",
"editor.lineHighlightBorder": "#1a1a1a",
"editor.lineHighlightBackground": "#490050",

View file

@ -39,6 +39,7 @@ list(APPEND RUNTIME_SOURCE_FILES
${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/hardware/CPUExtensions.cpp
${CMAKE_CURRENT_LIST_DIR}/src/tools/Utils.cpp
)
@ -57,6 +58,7 @@ list(APPEND DEBUGGER_SOURCE_FILES
${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/hardware/CPUExtensions.cpp
${CMAKE_CURRENT_LIST_DIR}/src/runtime/DragonRuntime.cpp
${CMAKE_CURRENT_LIST_DIR}/src/runtime/ConfigLoader.cpp

View file

@ -1 +1 @@
1581
1584

View file

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

View file

@ -3,10 +3,10 @@
#==========================================================================================================================================
0x0000 BIOS (4096 Bytes)
0x0000 BIOS (4096 Bytes) (write to this section is disabled)
0x0FFF
-------
0x1000 CMOS (128 Bytes)
0x1000 CMOS (128 Bytes) (write to this section is only allowed in BIOS Mode)
BootDisk: 0x0010
0x107F
-------
@ -18,7 +18,20 @@
...Repeat...
0x127F
-------
0x1280 KEYBOARD MAPPING (224 Bytes)
0x1280 KEYBOARD MAPPING (224 Bytes) (write to this section is only allowed in BIOS Mode)
0x00: Modifiers (2 bytes)
0b00000000.00000001: Left Shift
0b00000000.00000010: Left Ctrl
0b00000000.00000100: Left Alt
0b00000000.00001000: Left Super
0b00000000.00010000: Right Shift
0b00000000.00100000: Right Control
0b00000000.01000000: Right Alt
0b00000000.10000000: Right Super
0b00000001.00000000: Caps Lock
0b00000010.00000000: Num Lock
0b00000100.00000000: Scroll Lock
0x02: KeyCode (2 bytes)
0x135F
-------
0x1360 MOUSE MAPPING (32 Bytes)
@ -119,4 +132,8 @@ BIOS Specific - Software Interrupts:
Machine Specific - Hardware Interrupts:
=======================================
MAX INTERRUPT 0xAA
0x80: Disk Interface Finished
0xA0: Keyboard Interface - Key Pressed
0xA1: Keyboard Interface - Key Released
0xA2: Keyboard Interface - Text Entered

View file

@ -0,0 +1,57 @@
#ifndef __SOME_DEFINE__
#define __SOME_DEFINE__ 0
#include <file.dsh>
struct SomeStruct {
//var data1;
int data2;
int data3 = 0;
string data4 = "Hello"; //string type is basically a byte array with a 0 at the end
int[10] data6; //Array
int[] data7 = { 2, 5, 7 }; //Array
int* data8; //Pointer
SomeStruct* data9 = null;
};
fn main(void) -> int {
let myVar: SomeStruct;
(*myVar.data8) = 12;
let myVar2: int* = myVar.data8;
myFunction(myVar2, 10);
dstd::print("The result is %d!", (*myVar2));
}
fn myFunction(int* num1_ptr, int num2) -> void {
(*num1_ptr) = (*num1_ptr) + num2;
}
namespace dstd {
fn print(string fmt, var args@) -> int {
let _args_len: int = args_count(args);
let _args_counter: int = 0;
let _ctrl_char: bool = false;
let _ret_val: int = 0;
for (byte c in fmt) {
if (!_ctrl_char) {
_ret_val = __internal_dstd::__print_char_in_display_mode(__internal_dstd::__display_modes::__text_single_color, c);
continue;
}
if (c == '%') { _ctrl_char = true; continue; }
if (_ctrl_char) {
if (c == 'd') {
_ctrl_char = false;
if (_args_len < 1) {
continue;
}
let _integer: int = args_get_int(_args_counter);
_args_counter++;
_ret_val = __internal_dstd::__print_integer_in_display_mode(__internal_dstd::__display_modes::__text_single_color, _integer);
}
}
}
}
}
#endif

View file

@ -0,0 +1,102 @@
#ifndef __SOME_DEFINE__
#define __SOME_DEFINE__
#include <someFile.dsc>
#data_alloc(128) // Total data memory allocated
//Types: byte, word, word, string, bool
struct SomeStruct {
var data1: byte = 0;
var data2: word;
var data3: string = "Hello"; //Basically equivalent to var data3: byte[] = { 'H', 'e', 'l', 'l', 'o', 0 }
var data4: bool = false; //<true> and <false> are respectively replaced with <1> and <0>, and
//<bool> is actually equivalent to <byte>
var data5: byte[] = { 4, 1, 4, 2 };
var data6: word[10];
}
/** DASM Translation
@struct SomeStruct
data1:1 > 0x00
data2:4;
data3:6 > 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x00
data4:1 > 0x00
data5:4 > 0x04, 0x01, 0x04, 0x02
data6:20
@end
**/
fn testFunction(var param1:word, var param2:string) -> word {
if (length<param2> == 0) {
return 0;
} else {
return param1;
}
}
/** DASM Translation
__fn_testFunction_2_word_byteptr__:
arg R1 ## param1 (word)
arg R2 ## param2 (string)
mov ACC, 6
ret
**/
fn strlen(var str:string) -> word {
if (str == null) { return 0; }
var c:byte = str[0];
var counter:word = 0;
while (c != 0) {
counter++;
c = str[counter];
}
return counter;
}
fn strlen(var str:string) -> word {
dasm {
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
}
}
/** DASM Translation
__fn_strlen_1_byteptr__:
arg R1 ## param2 (string)
mov ACC, R1
jne $__fn_strlen_1_byteptr__branch_1_end__, 0
__fn_strlen_1_byteptr__branch_1__:
mov RV, 0
jmp $__fn_strlen_1_byteptr__end__
__fn_strlen_1_byteptr__branch_1_end__:
omovb *FP, *R1, -1 ## c
omov *FP, 0x0000, -3 ## counter
__fn_strlen_1_byteptr__loop_1__:
movbo ACC, *FP, -1
jeq, $__fn_strlen_1_byteptr__loop_1_end__, 0
movo ACC, *FP, -3
inc ACC
omov *FP, ACC, -3
omovb *FP, *ACC, -1
jmp $__fn_strlen_1_byteptr__loop_1__
__fn_strlen_1_byteptr__loop_1_end__:
movo RV, *FP, -3
__fn_strlen_1_byteptr__end__
ret
**/
#endif

View file

@ -0,0 +1,51 @@
Text visualization for hardware interrupts (in call-tree view)
Inverted Colors in Text-Single-Color
show where interrupts are disabled (in call-tree view)
***Add possibility to specify instruction sets in machine config
Add possibility to specify required instruction sets in dasm
Add "Extended mov" instruction set
Remove old offset mov
Implelemnt Instructions:
## Offset on first operand
omov *R1, 0xFAAB, 4 ## Move word immediate into (deref reg + immediate offset word)
omov *R1, 0xFAAB, R10 ## Move word immediate into (deref reg + reg offset)
omovb *R1, 0xFA, 4 ## Move byte immediate into (deref reg + immediate offset word)
omovb *R1, 0xFA, R10 ## Move byte immediate into (deref reg + reg offset)
omov *R1, *R2, 4 ## Move word deref reg into (deref reg + immediate offset word)
omov *R1, *R2, R10 ## Move word deref reg into (deref reg + reg offset)
omovb *R1, *R2, 4 ## Move byte deref reg into (deref reg + immediate offset word)
omovb *R1, *R2, R10 ## Move byte deref reg into (deref reg + reg offset)
omov R1, [0xFAAB], 4 ## Move word Memory into (reg + immediate offset word)
omov R1, [0xFAAB], R10 ## Move word Memory into (reg + reg offset)
omovb R1, [0xFAAB], 4 ## Move byte Memory into (reg + immediate offset word)
omovb R1, [0xFAAB], R10 ## Move byte Memory into (reg + reg offset)
omov R1, *R2, 4 ## Move word deref reg into (reg + immediate offset word)
omov R1, *R2, R10 ## Move word deref reg into (reg + reg offset)
omovb R1, *R2, 4 ## Move byte deref reg into (reg + immediate offset word)
omovb R1, *R2, R10 ## Move byte deref reg into (reg + reg offset)
omov [0x1800], 0xACAB, 4 ## Move word immediate into (Memory + immediate offset word)
omov [0x1800], 0xACAB, R10 ## Move word immediate into (Memory + reg offset)
omovb [0x1800], 0xAC, 4 ## Move byte immediate into (Memory + immediate offset word)
omovb [0x1800], 0xAC, R10 ## Move byte immediate into (Memory + reg offset)
## Offset on second operand
movo *R1, *R2, 4 ## Move word (deref reg + immediate offset word) into deref reg
movo *R1, *R2, R10 ## Move word (deref reg + reg offset) into deref reg
movbo *R1, *R2, 4 ## Move byte (deref reg + immediate offset word) into deref reg
movbo *R1, *R2, R10 ## Move byte (deref reg + reg offset) into deref reg
movo R1, [0xFAAB], 4 ## Move word (Memory + immediate offset word) into reg
movo R1, [0xFAAB], R10 ## Move word (Memory + reg offset) into reg
movbo R1, [0xFAAB], 4 ## Move byte (Memory + immediate offset word) into reg
movbo R1, [0xFAAB], R10 ## Move byte (Memory + reg offset) into reg
movo R1, *R2, 4 ## Move word (deref reg + immediate offset word) into reg
movo R1, *R2, R10 ## Move word (deref reg + reg offset) into reg
movbo R1, *R2, 4 ## Move byte (deref reg + immediate offset word) into reg
movbo R1, *R2, R10 ## Move byte (deref reg + reg offset) into reg
## Plus every (immediate offset) variant with byte offset instead of word offset

Binary file not shown.

View file

@ -41,6 +41,8 @@
@define S_REG_1 0x07
@define S_REG_2 0x08
@define S_REG_3 0x09
@define INST_BIOS_NODE_TOGGLE 0x02
## ===============================================================================================
.data

View file

@ -41,6 +41,7 @@
mov FL, ACC
## ----
%low INST_BIOS_NODE_TOGGLE 0x00 ## Disable BIOS Mode before leaving the BIOS
jmp MemoryAddresses.MBR ## Jump to start of MBR in memory
hlt ## Just in case somehow execution reaches this point
## ========================================================================

View file

@ -10,6 +10,23 @@
$string "Hello World!!"
.code
debug_break
%low 0xE0 0x01
mov R10, 0x00
mov R9, $_text_entered_handler
mov R8, 0xA2
int 0x20
mov R10, 0x00
mov R9, $_key_pressed_handler
mov R8, 0xA0
int 0x20
mov R10, 0x01
mov R9, 62
int 0x30
mov R1, 0 ## Zero the counter
infinite_loop:
inc R1 ## Increment the counter
@ -17,32 +34,57 @@ infinite_loop:
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
##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
##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
##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
##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
##int 0x30 ## BIOS Video Interrupt
jmp $infinite_loop ## jump to the beginning of infinite loop
hlt
_text_entered_handler:
mov R9, [0x1282]
mov R10, 0x01
int 0x30
rti
_key_pressed_handler:
mov ACC, [0x1282]
jeq $_key_pressed_handler_backspace, 8
jne $_key_pressed_handler_end, 13
mov R10, 0x02
int 0x30
mov R10, 0x01
mov R9, 62
int 0x30
jmp $_key_pressed_handler_end
_key_pressed_handler_backspace:
debug_break
mov R9, ACC
mov R10, 0x01
int 0x30
_key_pressed_handler_end:
rti
.fixed 512, 0x00

View file

@ -852,6 +852,25 @@ namespace dragon
m_labelTable["$" + lineEdit].address = m_dataSize + m_loadAddress + m_code.size() + 3;
continue;
}
else if (lineEdit.startsWith("%low ")) //Low level code injection
{
_disassembly_line.addr = m_dataSize + m_loadAddress + m_code.size() + 3;
lineEdit.substr(4).trim();
auto tok = lineEdit.tokenize();
for (auto& token : tok)
{
if (!token.isNumeric())
{
std::cout << "Invalid code in .low directive. Must be numeric byte strem, space-separated: " << line << "\n";
return;
}
m_code.push_back((int8_t)token.toInt());
}
_disassembly_line.code = lineEdit;
_disassembly_line.code.add(" (%low)");
m_disassembly.push_back(_disassembly_line);
continue;
}
else if (commaCount == 0 && spaceCount <= 0) //0 Operands
{
_disassembly_line.addr = m_dataSize + m_loadAddress + m_code.size() + 3;

View file

@ -136,6 +136,7 @@ namespace dragon
rgxrstr.fg("\\{|\\}|\\+|\\*|\\-|\\/|\\(|\\)|\\[|\\]", "Red"); //Operators
rgxrstr.fg("0x[0-9A-Fa-f]+|0b[0-1]+|(?<!\\w)[0-9]+(?!\\w)", "BrightYellow"); //Number Constants
rgxrstr.fg("(?<!\\w)(r[1-9]|r10|fl|pp|rv|fp|sp|ip|acc)(?!\\w)", "BrightGreen", true); //Registers
rgxrstr.fg("\\%low", "Magenta");
rgxrstr.col("\\$\\w+", "Cyan", "Black"); //Labels
ostd::String instEdit = rgxrstr.getRawString();
for (auto& label : labelList)
@ -181,6 +182,8 @@ namespace dragon
out.fg(ostd::ConsoleColors::Red);
else if (instHead == "nop")
out.fg(ostd::ConsoleColors::Gray);
else if(instHead.isNumeric())
out.fg(ostd::ConsoleColors::Magenta);
else
out.fg(ostd::ConsoleColors::Blue);
out.p(instHead.cpp_str());
@ -387,16 +390,16 @@ namespace dragon
//INT Handler
{
tmp = " ", tmpStyle = "";
tmp.add(STR_BOOL(minfo.previousInstructionInterruptHandler));
tmp.add(minfo.previousInstructionInterruptHandlerCount);
tmp.addPadding(item_len, ' ', ostd::String::ePaddingBehavior::AllowOddExtraLeft);
tmpStyle = "[@@style foreground:Blue]";
tmpStyle.add(tmp).add("[@@/]");
str.replaceAll("%PREV_INT_HANDLER%", tmpStyle);
tmp = " ";
tmp.add(STR_BOOL(minfo.currentInstructionInterruptHandler));
tmp.add(minfo.currentInstructionInterruptHandlerCount);
tmp.addPadding(item_len, ' ', ostd::String::ePaddingBehavior::AllowOddExtraLeft);
if (minfo.currentInstructionInterruptHandler != minfo.previousInstructionInterruptHandler)
if (minfo.currentInstructionInterruptHandlerCount != minfo.previousInstructionInterruptHandlerCount)
tmpStyle = "[@@style foreground:Black,background:BrightRed]";
else
tmpStyle = "[@@style foreground:Blue]";
@ -1052,6 +1055,11 @@ namespace dragon
call_str = ch_ang_u + "int " + ostd::Utils::getHexStr(call.addr, true, 1);
level++;
}
else if (call_info == "hw int")
{
call_str = ch_ang_u + "hwi " + ostd::Utils::getHexStr(call.addr, true, 1);
level++;
}
else if (call_info == "ret")
{
call_str = ch_ang_d + "ret";
@ -1067,9 +1075,9 @@ namespace dragon
if (call_info == "call reg")
subroutine_addr = "*" + subroutine_addr;
if (subroutine_name != "")
call_str = ch_ang_u + subroutine_name + " (" + subroutine_addr + ")";
call_str = ch_ang_u + "call " + subroutine_name + " (" + subroutine_addr + ")";
else
call_str = ch_ang_u + subroutine_addr;
call_str = ch_ang_u + "call " + subroutine_addr;
level++;
}
@ -1081,7 +1089,8 @@ namespace dragon
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("(?<![a-zA-Z\\_\\$\\.])hwi(?! [a-zA-Z\\_\\$\\.])", "Magenta");
rgx.fg("(?<![a-zA-Z\\_\\$\\.])call|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

View file

@ -21,7 +21,7 @@ namespace dragon
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");
setTypeName("dragon::Renderer");
enableSignals();
connectSignal(ostd::tBuiltinSignals::WindowResized);
validate();

View file

@ -42,7 +42,7 @@ namespace dragon
m_initialized = true;
m_running = true;
setTypeName("lspp::app::Window");
setTypeName("dragon::Window");
enableSignals(true);
validate();
@ -145,6 +145,21 @@ namespace dragon
MouseEventData mmd = l_getMouseState();
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::MouseReleased, ostd::tSignalPriority::RealTime, mmd);
}
else if (event.type == SDL_KEYDOWN)
{
KeyEventData ked(*this, (int32_t)event.key.keysym.sym, 0, KeyEventData::eKeyEvent::Pressed);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::KeyPressed, ostd::tSignalPriority::RealTime, ked);
}
else if (event.type == SDL_KEYUP)
{
KeyEventData ked(*this, (int32_t)event.key.keysym.sym, 0, KeyEventData::eKeyEvent::Released);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::KeyReleased, ostd::tSignalPriority::RealTime, ked);
}
else if (event.type == SDL_TEXTINPUT)
{
KeyEventData ked(*this, 0, event.text.text[0], KeyEventData::eKeyEvent::Text);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::TextEntered, ostd::tSignalPriority::RealTime, ked);
}
}
}
}

View file

@ -69,7 +69,7 @@ namespace dragon
public:
inline WindowResizedData(Window& parent, int32_t _oldx, int32_t _oldy, int32_t _newx, int32_t _newy) : parentWindow(parent), old_width(_oldx), old_height(_oldy), new_width(_newx), new_height(_newy)
{
setTypeName("lspp::app::WindowResizedData");
setTypeName("dragon::WindowResizedData");
validate();
}
@ -86,7 +86,7 @@ namespace dragon
public:
inline MouseEventData(Window& parent, int32_t mousex, int32_t mousey, eButton btn) : parentWindow(parent), position_x(mousex), position_y(mousey), button(btn)
{
setTypeName("lspp::app::MouseEventData");
setTypeName("dragon::MouseEventData");
validate();
}
@ -96,4 +96,20 @@ namespace dragon
eButton button;
Window& parentWindow;
};
class KeyEventData : public ostd::BaseObject
{
public: enum class eKeyEvent { Pressed = 0, Released, Text };
public:
inline KeyEventData(Window& parent, int32_t key, char _text, eKeyEvent evt) : parentWindow(parent), keyCode(key), text(_text), eventType(evt)
{
setTypeName("dragon::KeyEventData");
validate();
}
public:
int32_t keyCode;
char text;
eKeyEvent eventType;
Window& parentWindow;
};
}

View file

@ -0,0 +1,49 @@
#include "CPUExtensions.hpp"
#include "VirtualCPU.hpp"
namespace dragon
{
namespace hw
{
namespace cpuext
{
ostd::String ExtMov::getOpCodeString(uint8_t opCode)
{
switch (opCode)
{
case 0x01: return m_name + "_Test";
default: return "UNKNOWN_INST";
}
}
uint8_t ExtMov::getInstructionSIze(uint8_t opCode)
{
switch (opCode)
{
case 0x01: return 2;
default: return 0;
}
}
bool ExtMov::execute(VirtualCPU& vcpu)
{
uint8_t inst = vcpu.fetch8();
switch (inst)
{
case 0x01:
{
}
break;
default:
{
//TODO: Error
return false;
}
}
return true;
}
}
}
}

View file

@ -0,0 +1,21 @@
#pragma once
#include "../tools/GlobalData.hpp"
namespace dragon
{
namespace hw
{
namespace cpuext
{
class ExtMov : public data::CPUExtension
{
public:
inline ExtMov(void) : data::CPUExtension(data::OpCodes::Ext01, "extmov") { }
ostd::String getOpCodeString(uint8_t opCode) override;
uint8_t getInstructionSIze(uint8_t opCode) override;
bool execute(VirtualCPU& vcpu) override;
};
}
}
}

View file

@ -1,12 +1,12 @@
#pragma once
#include <ostd/Types.hpp>
#include <ostd/BaseObject.hpp>
namespace dragon
{
namespace hw
{
class IMemoryDevice
class IMemoryDevice : public ostd::BaseObject
{
public:
virtual int8_t read8(uint16_t addr) = 0;

View file

@ -5,6 +5,8 @@
#include <ostd/Utils.hpp>
#include <iostream>
#include "../runtime/DragonRuntime.hpp"
namespace dragon
{
namespace hw
@ -13,6 +15,9 @@ namespace dragon
{
writeRegister(data::Registers::SP, (uint16_t)(0xFFFF - 1));
writeRegister(data::Registers::FP, (uint16_t)(0xFFFF - 1));
for (int32_t i = 0; i < 16; i++)
m_extensions[i] = nullptr;
}
int16_t VirtualCPU::readRegister(uint8_t reg)
@ -31,6 +36,7 @@ namespace dragon
int8_t VirtualCPU::fetch8(void)
{
uint16_t nextInstAddr = readRegister(data::Registers::IP);
m_currentAddr = nextInstAddr;
int8_t inst = m_memory.read8(nextInstAddr);
writeRegister(data::Registers::IP, nextInstAddr + 1);
return inst;
@ -39,6 +45,7 @@ namespace dragon
int16_t VirtualCPU::fetch16(void)
{
uint16_t nextInstAddr = readRegister(data::Registers::IP);
m_currentAddr = nextInstAddr;
int16_t inst = m_memory.read16(nextInstAddr);
writeRegister(data::Registers::IP, nextInstAddr + 2);
return inst;
@ -143,27 +150,53 @@ namespace dragon
writeRegister(data::Registers::FL, m_tempFlags.value);
}
void VirtualCPU::handleInterrupt(uint8_t intValue)
void VirtualCPU::handleInterrupt(uint8_t intValue, bool hardware)
{
uint16_t entryPointer = data::MemoryMapAddresses::IntVector_Start + (intValue * 3);
uint8_t interruptStatus = m_memory.read8(entryPointer);
if (interruptStatus != 0xFF) return;
uint16_t handlerAddress = m_memory.read16(entryPointer + 1);
if (!m_isInInterruptHandler)
{
pushToStack(0);
pushStackFrame();
}
m_isInInterruptHandler = true;
m_subroutineCounter++;
m_interruptHandlerCount++;
writeRegister(data::Registers::IP, handlerAddress);
if (m_debugModeEnabled && hardware)
{
DragonRuntime::tCallInfo interruptData;
interruptData.info = "HW INT";
interruptData.addr = intValue;
interruptData.inst_addr = 0x0000;
ostd::SignalHandler::emitSignal(DragonRuntime::SignalListener::Signal_HardwareInterruptOccurred, ostd::tSignalPriority::RealTime, interruptData);
}
}
bool VirtualCPU::loadExtension(void)
{
if (m_currentInst < data::OpCodes::Ext01 || m_currentInst > data::OpCodes::Ext16)
return false;
for (int32_t i = 0; i < 16; i++)
{
if (m_extensions[i] == nullptr)
continue;
if (m_extensions[i]->m_code == m_currentInst)
{
m_currentExtension = m_extensions[i];
return true;
}
}
return false;
}
bool VirtualCPU::execute(void)
{
if (m_halt) return false;
m_currentExtension = nullptr;
m_isDebugBreakPoint = false;
uint8_t inst = fetch8();
m_currentInst = inst;
if (loadExtension())
return m_currentExtension->execute(*this);
switch (inst)
{
case data::OpCodes::NoOp:
@ -176,6 +209,16 @@ namespace dragon
m_isDebugBreakPoint = true;
}
break;
case data::OpCodes::BIOSModeImm:
{
uint16_t tmpAddr = m_currentAddr;
int8_t value = fetch8();
if (tmpAddr >= data::MemoryMapAddresses::BIOS_End)
m_biosMode = false;
else
m_biosMode = value != 0;
}
break;
case data::OpCodes::MovImmReg:
{
uint8_t regAddr = fetch8();
@ -744,7 +787,7 @@ namespace dragon
break;
case data::OpCodes::RetInt:
{
m_isInInterruptHandler = false;
m_interruptHandlerCount--;
popStackFrame();
// m_subroutineCounter = ZERO(m_subroutineCounter - 1);
m_subroutineCounter--;
@ -755,10 +798,32 @@ namespace dragon
uint8_t intValue = fetch8();
if (!readFlag(data::Flags::InterruptsEnabled))
return true;
handleInterrupt(intValue);
handleInterrupt(intValue, false);
m_subroutineCounter++;
}
break;
case data::OpCodes::Ext01:
case data::OpCodes::Ext02:
case data::OpCodes::Ext03:
case data::OpCodes::Ext04:
case data::OpCodes::Ext05:
case data::OpCodes::Ext06:
case data::OpCodes::Ext07:
case data::OpCodes::Ext08:
case data::OpCodes::Ext09:
case data::OpCodes::Ext10:
case data::OpCodes::Ext11:
case data::OpCodes::Ext12:
case data::OpCodes::Ext13:
case data::OpCodes::Ext14:
case data::OpCodes::Ext15:
case data::OpCodes::Ext16:
{
data::ErrorHandler::pushError(data::ErrorCodes::CPU_UnsupportedExtension, ostd::String("Unsupported Extension: ").add(ostd::Utils::getHexStr(inst, true, 1)));
m_halt = true;
return false;
}
break;
default:
{
data::ErrorHandler::pushError(data::ErrorCodes::CPU_UnknownInstruction, ostd::String("Unknown instruction: ").add(ostd::Utils::getHexStr(inst, true, 1)));

View file

@ -6,6 +6,7 @@
#include "IMemoryDevice.hpp"
#include "../debugger/Debugger.hpp"
#include "../tools/GlobalData.hpp"
namespace dragon
{
@ -31,13 +32,15 @@ namespace dragon
bool readFlag(uint8_t flg);
void setFlag(uint8_t flg, bool val = true);
void handleInterrupt(uint8_t intValue);
void handleInterrupt(uint8_t intValue, bool hardware);
bool loadExtension(void);
bool execute(void);
inline bool isHalted(void) const { return m_halt; }
inline uint8_t getCurrentInstruction(void) const { return m_currentInst; }
inline bool isInDebugBreakPoint(void) const { return m_isDebugBreakPoint; }
inline bool isInBIOSMOde(void) const { return m_biosMode; }
inline bool isInSubRoutine(void) const { return m_subroutineCounter > 0; }
inline int32_t getSubRoutineCounter(void) const { return m_subroutineCounter; }
@ -51,12 +54,16 @@ namespace dragon
uint16_t m_stackFrameSize { 0 };
bool m_halt { false };
uint8_t m_currentInst { 0x00 };
uint8_t m_currentAddr { 0x00 };
bool m_biosMode { true };
bool m_isInInterruptHandler { false };
int32_t m_interruptHandlerCount { 0 };
bool m_isDebugBreakPoint { false };
bool m_debugModeEnabled { false };
int32_t m_subroutineCounter { 0 };
data::CPUExtension* m_extensions[16];
data::CPUExtension* m_currentExtension { nullptr };
std::vector<ostd::String> m_debug_stackFrameStrings;
friend class dragon::DragonRuntime;

View file

@ -6,6 +6,13 @@
#include "VirtualCPU.hpp"
#include "VirtualRAM.hpp"
#include "../runtime/DragonRuntime.hpp"
//TODO: Fix all access functions (reads and writes) ensuring the address is not out of bounds.
// Right now the check is done, but just to push an error if out of bounds; the address
// gets still used even in that case, which is really dumb and will probably crash the
// runtime most of the time.
namespace dragon
{
namespace hw
@ -104,35 +111,247 @@ namespace dragon
VirtualKeyboard::VirtualKeyboard(void)
void VirtualKeyboard::init(void)
{
uint32_t dataSize = data::MemoryMapAddresses::Keyboard_End - data::MemoryMapAddresses::Keyboard_Start;
for (int32_t i = 0; i < dataSize; i++)
m_data.push_back(0x00);
enableSignals();
validate();
connectSignal(ostd::tBuiltinSignals::KeyPressed);
connectSignal(ostd::tBuiltinSignals::KeyReleased);
connectSignal(ostd::tBuiltinSignals::TextEntered);
}
int8_t VirtualKeyboard::read8(uint16_t addr)
{
return 0x00;
if (addr >= m_data.size())
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Byte KeyboardController location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
return m_data[addr];
}
int16_t VirtualKeyboard::read16(uint16_t addr)
{
return 0x0000;
if (addr >= m_data.size() - 1)
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Word KeyboardController location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
return ((m_data[addr + 0] << 8) & 0xFF00U)
| ( m_data[addr + 1] & 0x00FFU);
}
int8_t VirtualKeyboard::write8(uint16_t addr, int8_t value)
{
return 0x00;
if (addr >= m_data.size())
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Word KeyboardController location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
if (!DragonRuntime::cpu.isInBIOSMOde())
{
data::ErrorHandler::pushError(data::ErrorCodes::AccessViolation_BiosModeRequired, ostd::String("Attempting to write byte to KeyboardController while not in BIOS mode. Address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
return 0;
}
return __write8(addr, value);
}
int16_t VirtualKeyboard::write16(uint16_t addr, int16_t value)
{
return 0x0000;
if (addr >= m_data.size() - 1)
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Word KeyboardController location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
if (!DragonRuntime::cpu.isInBIOSMOde())
{
data::ErrorHandler::pushError(data::ErrorCodes::AccessViolation_BiosModeRequired, ostd::String("Attempting to write word to KeyboardController while not in BIOS mode. Address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
return 0;
}
return __write16(addr, value);
}
ostd::ByteStream* VirtualKeyboard::getByteStream(void)
{
return nullptr;
return &m_data;
}
void VirtualKeyboard::handleSignal(ostd::tSignal& signal)
{
auto& cpu = DragonRuntime::cpu;
const auto& state = SDL_GetKeyboardState(nullptr);
if (signal.ID == ostd::tBuiltinSignals::KeyPressed || signal.ID == ostd::tBuiltinSignals::KeyReleased)
{
KeyEventData& ked = (KeyEventData&)signal.userData;
m_modifiersBitFiels = __construct_modifiers_bitfield();
__write16(tRegisters::Modifiers, (int16_t)m_modifiersBitFiels.value);
__write16(tRegisters::KeyCode, __sdl_key_code_convert(ked.keyCode));
if (ked.eventType == KeyEventData::eKeyEvent::Pressed)
cpu.handleInterrupt(data::InterruptCodes::KeyPressed, true);
else if (ked.eventType == KeyEventData::eKeyEvent::Pressed)
cpu.handleInterrupt(data::InterruptCodes::KeyReleased, true);
}
else if (signal.ID == ostd::tBuiltinSignals::TextEntered)
{
KeyEventData& ked = (KeyEventData&)signal.userData;
m_modifiersBitFiels = __construct_modifiers_bitfield();
__write16(tRegisters::Modifiers, (int16_t)m_modifiersBitFiels.value);
__write16(tRegisters::KeyCode, (int16_t)ked.text);
cpu.handleInterrupt(data::InterruptCodes::TextEntered, true);
}
}
ostd::BitField_16 VirtualKeyboard::__construct_modifiers_bitfield(void)
{
ostd::BitField_16 bitfield;
auto mod_state = SDL_GetModState();
ostd::Bits::val(bitfield, tModifierBits::LeftShift, (mod_state & KMOD_LSHIFT));
ostd::Bits::val(bitfield, tModifierBits::LeftControl, (mod_state & KMOD_LCTRL));
ostd::Bits::val(bitfield, tModifierBits::LeftAlt, (mod_state & KMOD_LALT));
ostd::Bits::val(bitfield, tModifierBits::LeftSuper, (mod_state & KMOD_LGUI));
ostd::Bits::val(bitfield, tModifierBits::RightShift, (mod_state & KMOD_RSHIFT));
ostd::Bits::val(bitfield, tModifierBits::RightControl, (mod_state & KMOD_RCTRL));
ostd::Bits::val(bitfield, tModifierBits::RightAlt, (mod_state & KMOD_RALT));
ostd::Bits::val(bitfield, tModifierBits::RightSuper, (mod_state & KMOD_RGUI));
ostd::Bits::val(bitfield, tModifierBits::CapsLock, (mod_state & KMOD_CAPS));
ostd::Bits::val(bitfield, tModifierBits::NumLock, (mod_state & KMOD_NUM));
ostd::Bits::val(bitfield, tModifierBits::ScrolLLock, (mod_state & KMOD_SCROLL));
return bitfield;
}
int8_t VirtualKeyboard::__write8(uint16_t addr, int8_t value)
{
m_data[addr] = value;
return value;
}
int16_t VirtualKeyboard::__write16(uint16_t addr, int16_t value)
{
m_data[addr + 0] = (value >> 8) & 0xFF;
m_data[addr + 1] = value & 0xFF;
return value;
}
int16_t VirtualKeyboard::__sdl_key_code_convert(int32_t keyCode)
{
switch (keyCode)
{
case SDLK_LCTRL: return (int16_t)eKeys::LeftCTRL;
case SDLK_LSHIFT: return (int16_t)eKeys::LeftShift;
case SDLK_LALT: return (int16_t)eKeys::LeftALT;
case SDLK_LGUI: return (int16_t)eKeys::LeftSuper;
case SDLK_RCTRL: return (int16_t)eKeys::RightCTRL;
case SDLK_RSHIFT: return (int16_t)eKeys::RightShift;
case SDLK_RGUI: return (int16_t)eKeys::RightSuper;
case SDLK_RALT: return (int16_t)eKeys::RightALT;
case SDLK_KP_DIVIDE: return (int16_t)eKeys::KeyPadDivide;
case SDLK_KP_MULTIPLY: return (int16_t)eKeys::KeyPadMultiply;
case SDLK_KP_MINUS: return (int16_t)eKeys::KeyPadMinus;
case SDLK_KP_PLUS: return (int16_t)eKeys::KeyPadPlus;
case SDLK_KP_ENTER: return (int16_t)eKeys::KeyPadEnter;
case SDLK_KP_1: return (int16_t)eKeys::KeyPad1;
case SDLK_KP_2: return (int16_t)eKeys::KeyPad2;
case SDLK_KP_3: return (int16_t)eKeys::KeyPad3;
case SDLK_KP_4: return (int16_t)eKeys::KeyPad4;
case SDLK_KP_5: return (int16_t)eKeys::KeyPad5;
case SDLK_KP_6: return (int16_t)eKeys::KeyPad6;
case SDLK_KP_7: return (int16_t)eKeys::KeyPad7;
case SDLK_KP_8: return (int16_t)eKeys::KeyPad8;
case SDLK_KP_9: return (int16_t)eKeys::KeyPad9;
case SDLK_KP_0: return (int16_t)eKeys::KeyPad0;
case SDLK_KP_PERIOD: return (int16_t)eKeys::KeyPadPeriod;
case SDLK_PRINTSCREEN: return (int16_t)eKeys::PrintScreen;
case SDLK_INSERT: return (int16_t)eKeys::Insert;
case SDLK_HOME: return (int16_t)eKeys::Home;
case SDLK_PAGEUP: return (int16_t)eKeys::PageUp;
case SDLK_END: return (int16_t)eKeys::End;
case SDLK_PAGEDOWN: return (int16_t)eKeys::PageDown;
case SDLK_RIGHT: return (int16_t)eKeys::RightArrow;
case SDLK_LEFT: return (int16_t)eKeys::LeftArrow;
case SDLK_DOWN: return (int16_t)eKeys::DownArrow;
case SDLK_UP: return (int16_t)eKeys::UpArrow;
case SDLK_CAPSLOCK: return (int16_t)eKeys::CapsLock;
case SDLK_NUMLOCKCLEAR: return (int16_t)eKeys::NumLock;
case SDLK_SCROLLLOCK: return (int16_t)eKeys::ScrollLock;
case SDLK_F1: return (int16_t)eKeys::F1;
case SDLK_F2: return (int16_t)eKeys::F2;
case SDLK_F3: return (int16_t)eKeys::F3;
case SDLK_F4: return (int16_t)eKeys::F4;
case SDLK_F5: return (int16_t)eKeys::F5;
case SDLK_F6: return (int16_t)eKeys::F6;
case SDLK_F7: return (int16_t)eKeys::F7;
case SDLK_F8: return (int16_t)eKeys::F8;
case SDLK_F9: return (int16_t)eKeys::F9;
case SDLK_F10: return (int16_t)eKeys::F10;
case SDLK_F11: return (int16_t)eKeys::F11;
case SDLK_F12: return (int16_t)eKeys::F12;
case SDLK_DELETE: return (int16_t)eKeys::Delete;
case SDLK_RETURN: return (int16_t)eKeys::Return;
case SDLK_ESCAPE: return (int16_t)eKeys::Escape;
case SDLK_BACKSPACE: return (int16_t)eKeys::Backspace;
case SDLK_TAB: return (int16_t)eKeys::Tab;
case SDLK_SPACE: return (int16_t)eKeys::Spacebar;
case SDLK_EXCLAIM: return (int16_t)eKeys::ExclamationMark;
case SDLK_QUOTEDBL: return (int16_t)eKeys::DoubleQuote;
case SDLK_HASH: return (int16_t)eKeys::Hash;
case SDLK_PERCENT: return (int16_t)eKeys::Percent;
case SDLK_DOLLAR: return (int16_t)eKeys::DollarSign;
case SDLK_AMPERSAND: return (int16_t)eKeys::Ampersand;
case SDLK_QUOTE: return (int16_t)eKeys::SingleQuote;
case SDLK_LEFTPAREN: return (int16_t)eKeys::LeftParenthesis;
case SDLK_RIGHTPAREN: return (int16_t)eKeys::RightParenthesis;
case SDLK_ASTERISK: return (int16_t)eKeys::Asterisk;
case SDLK_PLUS: return (int16_t)eKeys::Plus;
case SDLK_COMMA: return (int16_t)eKeys::Comma;
case SDLK_MINUS: return (int16_t)eKeys::Minus;
case SDLK_PERIOD: return (int16_t)eKeys::Period;
case SDLK_SLASH: return (int16_t)eKeys::ForwardSlash;
case SDLK_0: return (int16_t)eKeys::Num0;
case SDLK_1: return (int16_t)eKeys::Num1;
case SDLK_2: return (int16_t)eKeys::Num2;
case SDLK_3: return (int16_t)eKeys::Num3;
case SDLK_4: return (int16_t)eKeys::Num4;
case SDLK_5: return (int16_t)eKeys::Num5;
case SDLK_6: return (int16_t)eKeys::Num6;
case SDLK_7: return (int16_t)eKeys::Num7;
case SDLK_8: return (int16_t)eKeys::Num8;
case SDLK_9: return (int16_t)eKeys::Num9;
case SDLK_COLON: return (int16_t)eKeys::Colon;
case SDLK_SEMICOLON: return (int16_t)eKeys::Semicolon;
case SDLK_LESS: return (int16_t)eKeys::LessThan;
case SDLK_EQUALS: return (int16_t)eKeys::Equals;
case SDLK_GREATER: return (int16_t)eKeys::GreaterThan;
case SDLK_QUESTION: return (int16_t)eKeys::QuestionMark;
case SDLK_AT: return (int16_t)eKeys::AtSign;
case SDLK_LEFTBRACKET: return (int16_t)eKeys::LeftBracket;
case SDLK_BACKSLASH: return (int16_t)eKeys::BackSlash;
case SDLK_RIGHTBRACKET: return (int16_t)eKeys::RightBracket;
case SDLK_CARET: return (int16_t)eKeys::Caret;
case SDLK_UNDERSCORE: return (int16_t)eKeys::Underscore;
case SDLK_BACKQUOTE: return (int16_t)eKeys::BackQuote;
case SDLK_a: return (int16_t)eKeys::LowerCase_a;
case SDLK_b: return (int16_t)eKeys::LowerCase_b;
case SDLK_c: return (int16_t)eKeys::LowerCase_c;
case SDLK_d: return (int16_t)eKeys::LowerCase_d;
case SDLK_e: return (int16_t)eKeys::LowerCase_e;
case SDLK_f: return (int16_t)eKeys::LowerCase_f;
case SDLK_g: return (int16_t)eKeys::LowerCase_g;
case SDLK_h: return (int16_t)eKeys::LowerCase_h;
case SDLK_i: return (int16_t)eKeys::LowerCase_i;
case SDLK_j: return (int16_t)eKeys::LowerCase_j;
case SDLK_k: return (int16_t)eKeys::LowerCase_k;
case SDLK_l: return (int16_t)eKeys::LowerCase_l;
case SDLK_m: return (int16_t)eKeys::LowerCase_m;
case SDLK_n: return (int16_t)eKeys::LowerCase_n;
case SDLK_o: return (int16_t)eKeys::LowerCase_o;
case SDLK_p: return (int16_t)eKeys::LowerCase_p;
case SDLK_q: return (int16_t)eKeys::LowerCase_q;
case SDLK_r: return (int16_t)eKeys::LowerCase_r;
case SDLK_s: return (int16_t)eKeys::LowerCase_s;
case SDLK_t: return (int16_t)eKeys::LowerCase_t;
case SDLK_u: return (int16_t)eKeys::LowerCase_u;
case SDLK_v: return (int16_t)eKeys::LowerCase_v;
case SDLK_w: return (int16_t)eKeys::LowerCase_w;
case SDLK_x: return (int16_t)eKeys::LowerCase_x;
case SDLK_y: return (int16_t)eKeys::LowerCase_y;
case SDLK_z: return (int16_t)eKeys::LowerCase_z;
default: return (int16_t)eKeys::UpperCase_A;
}
return (int16_t)eKeys::UpperCase_A;
}
@ -368,7 +587,7 @@ namespace dragon
m_data.w_Byte(tRegisters::Status, tStatusValues::Free);
m_data.w_Byte(tRegisters::Signal, tSignalValues::Ignore);
m_busy = false;
m_cpu.handleInterrupt(data::InterruptCodes::DiskInterfaceFFinished);
m_cpu.handleInterrupt(data::InterruptCodes::DiskInterfaceFFinished, true);
return;
}
currentAddress++;
@ -594,6 +813,11 @@ namespace dragon
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_InvalidAddress, ostd::String("Invalid Byte CMOS location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
return 0;
}
if (!DragonRuntime::cpu.isInBIOSMOde())
{
data::ErrorHandler::pushError(data::ErrorCodes::AccessViolation_BiosModeRequired, ostd::String("Attempting to write byte to CMOS while not in BIOS mode. Address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
return 0;
}
m_dataFile.seekp(addr);
m_dataFile.write((char*)(&value), sizeof(value));
return value;
@ -611,6 +835,11 @@ namespace dragon
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_InvalidAddress, ostd::String("Invalid Word CMOS location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
return 0;
}
if (!DragonRuntime::cpu.isInBIOSMOde())
{
data::ErrorHandler::pushError(data::ErrorCodes::AccessViolation_BiosModeRequired, ostd::String("Attempting to write word to CMOS while not in BIOS mode. Address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
return 0;
}
int8_t b1 = (value >> 8) & 0xFF;
int8_t b2 = (value & 0xFF);
write8(addr, b1);

View file

@ -14,7 +14,6 @@ namespace dragon
class VirtualCPU;
class VirtualRAM;
class VirtualBIOS : public IMemoryDevice
{
public:
@ -48,8 +47,184 @@ namespace dragon
};
class VirtualKeyboard : public IMemoryDevice
{
public: enum class eKeys
{
Delete = (int16_t)'\x7F',
Return = (int16_t)'\r',
Escape = (int16_t)'\x1B',
Backspace = (int16_t)'\b',
Tab = (int16_t)'\t',
Spacebar = (int16_t)' ',
ExclamationMark = (int16_t)'!',
DoubleQuote = (int16_t)'"',
Hash = (int16_t)'#',
Percent = (int16_t)'%',
DollarSign = (int16_t)'$',
Ampersand = (int16_t)'&',
SingleQuote = (int16_t)'\'',
LeftParenthesis = (int16_t)'(',
RightParenthesis = (int16_t)')',
Asterisk = (int16_t)'*',
Plus = (int16_t)'+',
Comma = (int16_t)',',
Minus = (int16_t)'-',
Period = (int16_t)'.',
ForwardSlash = (int16_t)'/',
Num0 = (int16_t)'0',
Num1 = (int16_t)'1',
Num2 = (int16_t)'2',
Num3 = (int16_t)'3',
Num4 = (int16_t)'4',
Num5 = (int16_t)'5',
Num6 = (int16_t)'6',
Num7 = (int16_t)'7',
Num8 = (int16_t)'8',
Num9 = (int16_t)'9',
Colon = (int16_t)':',
Semicolon = (int16_t)';',
LessThan = (int16_t)'<',
Equals = (int16_t)'=',
GreaterThan = (int16_t)'>',
QuestionMark = (int16_t)'?',
AtSign = (int16_t)'@',
UpperCase_A = (int16_t)'A',
UpperCase_B = (int16_t)'B',
UpperCase_C = (int16_t)'C',
UpperCase_D = (int16_t)'D',
UpperCase_E = (int16_t)'E',
UpperCase_F = (int16_t)'F',
UpperCase_G = (int16_t)'G',
UpperCase_H = (int16_t)'H',
UpperCase_I = (int16_t)'I',
UpperCase_J = (int16_t)'J',
UpperCase_K = (int16_t)'K',
UpperCase_L = (int16_t)'L',
UpperCase_M = (int16_t)'M',
UpperCase_N = (int16_t)'N',
UpperCase_O = (int16_t)'O',
UpperCase_P = (int16_t)'P',
UpperCase_Q = (int16_t)'Q',
UpperCase_R = (int16_t)'R',
UpperCase_S = (int16_t)'S',
UpperCase_T = (int16_t)'T',
UpperCase_U = (int16_t)'U',
UpperCase_V = (int16_t)'V',
UpperCase_W = (int16_t)'W',
UpperCase_X = (int16_t)'X',
UpperCase_Y = (int16_t)'Y',
UpperCase_Z = (int16_t)'Z',
LeftBracket = (int16_t)'[',
BackSlash = (int16_t)'\\',
RightBracket = (int16_t)']',
Caret = (int16_t)'^',
Underscore = (int16_t)'_',
BackQuote = (int16_t)'`',
LowerCase_a = (int16_t)'a',
LowerCase_b = (int16_t)'b',
LowerCase_c = (int16_t)'c',
LowerCase_d = (int16_t)'d',
LowerCase_e = (int16_t)'e',
LowerCase_f = (int16_t)'f',
LowerCase_g = (int16_t)'g',
LowerCase_h = (int16_t)'h',
LowerCase_i = (int16_t)'i',
LowerCase_j = (int16_t)'j',
LowerCase_k = (int16_t)'k',
LowerCase_l = (int16_t)'l',
LowerCase_m = (int16_t)'m',
LowerCase_n = (int16_t)'n',
LowerCase_o = (int16_t)'o',
LowerCase_p = (int16_t)'p',
LowerCase_q = (int16_t)'q',
LowerCase_r = (int16_t)'r',
LowerCase_s = (int16_t)'s',
LowerCase_t = (int16_t)'t',
LowerCase_u = (int16_t)'u',
LowerCase_v = (int16_t)'v',
LowerCase_w = (int16_t)'w',
LowerCase_x = (int16_t)'x',
LowerCase_y = (int16_t)'y',
LowerCase_z = (int16_t)'z',
LeftCTRL = (int16_t)0x0100,
RightCTRL = (int16_t)0x0101,
LeftALT = (int16_t)0x0102,
RightALT = (int16_t)0x0103,
LeftShift = (int16_t)0x0104,
RightShift = (int16_t)0x0105,
KeyPadDivide = (int16_t)0x0106,
KeyPadMultiply = (int16_t)0x0107,
KeyPadMinus = (int16_t)0x0108,
KeyPadPlus = (int16_t)0x0109,
KeyPadEnter = (int16_t)0x010A,
KeyPad1 = (int16_t)0x010B,
KeyPad2 = (int16_t)0x010C,
KeyPad3 = (int16_t)0x010D,
KeyPad4 = (int16_t)0x010E,
KeyPad5 = (int16_t)0x010F,
KeyPad6 = (int16_t)0x0110,
KeyPad7 = (int16_t)0x0111,
KeyPad8 = (int16_t)0x0112,
KeyPad9 = (int16_t)0x0113,
KeyPad0 = (int16_t)0x0114,
KeyPadPeriod = (int16_t)0x0115,
PrintScreen = (int16_t)0x0116,
Insert = (int16_t)0x0117,
Home = (int16_t)0x0118,
PageUp = (int16_t)0x0119,
End = (int16_t)0x011A,
PageDown = (int16_t)0x011B,
RightArrow = (int16_t)0x011C,
LeftArrow = (int16_t)0x011D,
DownArrow = (int16_t)0x011E,
UpArrow = (int16_t)0x011F,
CapsLock = (int16_t)0x0120,
NumLock = (int16_t)0x0121,
ScrollLock = (int16_t)0x0122,
F1 = (int16_t)0x0123,
F2 = (int16_t)0x0124,
F3 = (int16_t)0x0125,
F4 = (int16_t)0x0126,
F5 = (int16_t)0x0127,
F6 = (int16_t)0x0128,
F7 = (int16_t)0x0129,
F8 = (int16_t)0x012A,
F9 = (int16_t)0x012B,
F10 = (int16_t)0x012C,
F11 = (int16_t)0x012D,
F12 = (int16_t)0x012E,
LeftSuper = (int16_t)0x012F,
RightSuper = (int16_t)0x0130,
};
public: struct tModifierBits
{
inline static constexpr uint8_t LeftShift = 0;
inline static constexpr uint8_t LeftControl = 1;
inline static constexpr uint8_t LeftAlt = 2;
inline static constexpr uint8_t LeftSuper = 3;
inline static constexpr uint8_t RightShift = 4;
inline static constexpr uint8_t RightControl = 5;
inline static constexpr uint8_t RightAlt = 6;
inline static constexpr uint8_t RightSuper = 7;
inline static constexpr uint8_t CapsLock = 8;
inline static constexpr uint8_t NumLock = 9;
inline static constexpr uint8_t ScrolLLock = 10;
};
public: struct tRegisters
{
inline static constexpr uint16_t Modifiers = 0x00;
inline static constexpr uint16_t KeyCode = 0x02;
};
public:
VirtualKeyboard(void);
inline VirtualKeyboard(void) { }
void init(void);
int8_t read8(uint16_t addr) override;
int16_t read16(uint16_t addr) override;
int8_t write8(uint16_t addr, int8_t value) override;
@ -57,7 +232,17 @@ namespace dragon
ostd::ByteStream* getByteStream(void) override;
void handleSignal(ostd::tSignal& signal) override;
private:
ostd::BitField_16 __construct_modifiers_bitfield(void);
int8_t __write8(uint16_t addr, int8_t value);
int16_t __write16(uint16_t addr, int16_t value);
int16_t __sdl_key_code_convert(int32_t keyCode);
private:
ostd::ByteStream m_data;
ostd::BitField_16 m_modifiersBitFiels;
};
class VirtualMouse : public IMemoryDevice
{

View file

@ -1,6 +1,7 @@
#include "ConfigLoader.hpp"
#include <ostd/File.hpp>
#include <ostd/Utils.hpp>
#include "../hardware/CPUExtensions.hpp"
namespace dragon
{
@ -30,6 +31,23 @@ namespace dragon
config.vdisk_paths[disk_nr++] = lineEdit;
}
}
else if (lineEdit == "cpuext")
{
lineEdit = tokens.next();
tokens = lineEdit.tokenize(",");
if (tokens.count() == 0) continue; //TODO: Warning
int32_t ext_nr = 0;
while (tokens.hasNext())
{
if (ext_nr >= 16) break; //TODO: Warning
lineEdit = tokens.next();
if (lineEdit == "extmov")
{
config.cpuext_list[ext_nr++] = new hw::cpuext::ExtMov;
}
else continue; //TODO: Warning
}
}
else if (lineEdit == "bios")
{
lineEdit = tokens.next();

View file

@ -2,18 +2,21 @@
#include <ostd/Color.hpp>
#include <map>
#include "../tools/GlobalData.hpp"
namespace dragon
{
struct tMachineConfig
{
std::map<int32_t, ostd::String> vdisk_paths;
std::map<int32_t, data::CPUExtension*> cpuext_list;
ostd::String bios_path;
ostd::String cmos_path;
ostd::Color singleColor_background;
ostd::Color singleColor_foreground;
inline bool isValid(void) const { return m_valid; }
inline void destroy(void) { for (auto& ptr : cpuext_list) delete ptr.second; }
private:
bool m_valid { false };

View file

@ -4,6 +4,26 @@
namespace dragon
{
void DragonRuntime::SignalListener::init(void)
{
setTypeName("dragon::DragonRuntime::SignalListener");
validate();
enableSignals();
connectSignal(Signal_HardwareInterruptOccurred);
}
void DragonRuntime::SignalListener::handleSignal(ostd::tSignal& signal)
{
if (signal.ID == Signal_HardwareInterruptOccurred)
{
tCallInfo& interruptData = (tCallInfo&)signal.userData;
DragonRuntime::s_machineInfo.callStack.push_back(interruptData);
}
}
void DragonRuntime::printRegisters(dragon::hw::VirtualCPU& cpu)
{
out.fg("green").p("IP: ").fg("white").p(ostd::Utils::getHexStr(cpu.readRegister(dragon::data::Registers::IP), true, 2).cpp_str());
@ -129,6 +149,8 @@ namespace dragon
bool debugModeEnabled)
{
ostd::SignalHandler::init();
s_signalListener.init();
vKeyboard.init();
if (verbose)
out.fg(ostd::ConsoleColors::Magenta).p("Loading machine config: ").fg(ostd::ConsoleColors::BrightYellow).p(configFilePath.cpp_str()).nl();
machine_config = dragon::MachineConfigLoader::loadConfig(configFilePath);
@ -210,7 +232,7 @@ namespace dragon
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, "Keyb.");
memMap.mapDevice(vKeyboard, dragon::data::MemoryMapAddresses::Keyboard_Start, dragon::data::MemoryMapAddresses::Keyboard_End, true, "Keyb.");
if (verbose)
{
out.fg(ostd::ConsoleColors::Magenta).p(" vMouse: ");
@ -290,12 +312,33 @@ namespace dragon
out.fg(ostd::ConsoleColors::BrightYellow).p(" Debug mode enabled: ").p(STR_BOOL(debugModeEnabled)).nl();
cpu.m_debugModeEnabled = debugModeEnabled;
if (verbose)
out.fg(ostd::ConsoleColors::BrightYellow).p(" BIOS mode enabled").nl();
cpu.m_biosMode = true;
if (machine_config.cpuext_list.size() > 0)
{
if (verbose)
out.fg(ostd::ConsoleColors::BrightYellow).p(" Loading CPU Extensions").nl();
for (auto& ext : machine_config.cpuext_list)
{
cpu.m_extensions[ext.first] = ext.second;
if (verbose)
out.fg(ostd::ConsoleColors::BrightYellow).p(" ").p(ext.first + 1).p(": ").p(ext.second->m_name).nl();
}
}
out.nl().nl();
s_trackMachineInfo = trackMachineInfoDiff;
s_trackCallStack = trackCallStack;
return RETURN_VAL_EXIT_SUCCESS;
}
void DragonRuntime::shutdownMachine(void)
{
machine_config.destroy();
}
void DragonRuntime::runMachine(int32_t cycleLimit, bool basic_debug, bool step_exec)
{
int32_t cycleCounter = 0;
@ -412,7 +455,7 @@ namespace dragon
bool debugBreak = cpu.m_isDebugBreakPoint;
bool intHandler = cpu.m_isInInterruptHandler;
int32_t intHandlerCount = cpu.m_interruptHandlerCount;
bool biosMode = cpu.m_biosMode;
bool isInSubRoutine = cpu.isInSubRoutine();
@ -434,7 +477,7 @@ namespace dragon
minfo.previousInstructionTrackedValues.push_back(memMap.read8(addr));
minfo.previousInstructionDebugBreak = debugBreak;
minfo.previousInstructionInterruptHandler = intHandler;
minfo.previousInstructionInterruptHandlerCount = intHandlerCount;
minfo.previousInstructionBiosMode = biosMode;
minfo.previousIsInSubRoutine = isInSubRoutine;
}
@ -456,7 +499,7 @@ namespace dragon
minfo.currentInstructionTrackedValues.push_back(memMap.read8(addr));
minfo.currentInstructionDebugBreak = debugBreak;
minfo.currentInstructionInterruptHandler = intHandler;
minfo.currentInstructionInterruptHandlerCount = intHandlerCount;
minfo.currentInstructionBiosMode = biosMode;
minfo.currentIsInSubRoutine = isInSubRoutine;
}

View file

@ -17,8 +17,20 @@ namespace dragon
{
class DragonRuntime
{
public: struct tCallInfo
public: class SignalListener : public ostd::BaseObject
{
public:
inline SignalListener(void) { }
void init(void);
void handleSignal(ostd::tSignal& signal) override;
public:
inline static const int32_t Signal_HardwareInterruptOccurred = ostd::SignalHandler::newCustomSignal(8129);
};
public: struct tCallInfo : public ostd::BaseObject
{
inline tCallInfo(void) { }
inline tCallInfo(const ostd::String& _info, uint16_t _addr, uint16_t _inst_addr) : info(_info), addr(_addr), inst_addr(_inst_addr) { }
ostd::String info;
uint16_t addr;
uint16_t inst_addr;
@ -54,6 +66,8 @@ namespace dragon
int8_t currentInstructionFootprint[5] { 0x00, 0x00, 0x00, 0x00, 0x00 };
int16_t previousInstructionRegisters[20] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int16_t currentInstructionRegisters[20] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int32_t previousInstructionInterruptHandlerCount { 0 };
int32_t currentInstructionInterruptHandlerCount { 0 };
std::vector<uint16_t> trackedAddresses;
std::vector<int8_t> previousInstructionTrackedValues;
@ -61,8 +75,6 @@ namespace dragon
bool previousInstructionDebugBreak { false };
bool currentInstructionDebugBreak { false };
bool previousInstructionInterruptHandler { false };
bool currentInstructionInterruptHandler { false };
bool previousInstructionBiosMode { false };
bool currentInstructionBiosMode { false };
bool previousIsInSubRoutine { false };
@ -84,6 +96,7 @@ namespace dragon
bool hideVirtualDisplay = false,
bool rackCallStack = false,
bool debugModeEnabled = false);
static void shutdownMachine(void);
static void runMachine(int32_t cycleLimit, bool basic_debug, bool step_exec);
static bool runStep(std::vector<uint16_t> trackedAddresses = { });
static void forceLoad(const ostd::String& filePath, uint16_t loadAddress);
@ -123,6 +136,7 @@ namespace dragon
inline static tMachineDebugInfo s_machineInfo;
inline static bool s_trackMachineInfo { false };
inline static bool s_trackCallStack { false };
inline static SignalListener s_signalListener;
public:
inline static const int32_t RETURN_VAL_CLOSE_DEBUGGER = 128;
@ -133,5 +147,7 @@ namespace dragon
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;
friend class SignalListener;
};
}

View file

@ -5,6 +5,7 @@
namespace dragon
{
namespace hw { class VirtualCPU; }
namespace data
{
typedef uint32_t VDiskID;
@ -13,10 +14,12 @@ namespace dragon
{
public:
inline static constexpr uint64_t NoError = 0x0000000000000000;
inline static constexpr uint64_t AccessViolation_BiosModeRequired = 0x0000000000000001;
inline static constexpr uint64_t MM_RegionNotFound = 0x1000000000000000;
inline static constexpr uint64_t CPU_UnknownInstruction = 0x2000000000000000;
inline static constexpr uint64_t CPU_UnsupportedExtension = 0x2000000000000001;
inline static constexpr uint64_t BIOS_FailedToLoad = 0x3000000000000000;
inline static constexpr uint64_t BIOS_InvalidSize = 0x3000000000000001;
@ -188,14 +191,31 @@ namespace dragon
{
public:
inline static constexpr uint8_t DiskInterfaceFFinished = 0x80;
inline static constexpr uint8_t KeyPressed = 0xA0;
inline static constexpr uint8_t KeyReleased = 0xA1;
inline static constexpr uint8_t TextEntered = 0xA2;
};
class CPUExtension
{
public:
inline virtual ~CPUExtension(void) { }
inline CPUExtension(uint8_t code, ostd::String name) : m_code(code), m_name(name) { }
virtual ostd::String getOpCodeString(uint8_t opCode) = 0;
virtual uint8_t getInstructionSIze(uint8_t opCode) = 0;
virtual bool execute(hw::VirtualCPU& vcpu) = 0;
public:
uint8_t m_code { 0x00 };
ostd::String m_name { "" };
};
class OpCodes
{
public:
inline static constexpr uint8_t NoOp = 0x00;
inline static constexpr uint8_t DEBUG_Break = 0x01;
inline static constexpr uint8_t BIOSModeImm = 0x02;
inline static constexpr uint8_t MovImmReg = 0x10;
inline static constexpr uint8_t MovRegReg = 0x11;
@ -269,16 +289,36 @@ namespace dragon
inline static constexpr uint8_t JmpLeReg = 0x7B;
inline static constexpr uint8_t Jmp = 0x7C;
inline static constexpr uint8_t Ext01 = 0xE0;
inline static constexpr uint8_t Ext02 = 0xE1;
inline static constexpr uint8_t Ext03 = 0xE2;
inline static constexpr uint8_t Ext04 = 0xE3;
inline static constexpr uint8_t Ext05 = 0xE4;
inline static constexpr uint8_t Ext06 = 0xE5;
inline static constexpr uint8_t Ext07 = 0xE6;
inline static constexpr uint8_t Ext08 = 0xE7;
inline static constexpr uint8_t Ext09 = 0xE8;
inline static constexpr uint8_t Ext10 = 0xE9;
inline static constexpr uint8_t Ext11 = 0xEA;
inline static constexpr uint8_t Ext12 = 0xEB;
inline static constexpr uint8_t Ext13 = 0xEC;
inline static constexpr uint8_t Ext14 = 0xED;
inline static constexpr uint8_t Ext15 = 0xEE;
inline static constexpr uint8_t Ext16 = 0xEF;
inline static constexpr uint8_t RetInt = 0xFD;
inline static constexpr uint8_t Int = 0xFE;
inline static constexpr uint8_t Halt = 0xFF;
inline static ostd::String getOpCodeString(uint8_t opCode)
inline static ostd::String getOpCodeString(uint8_t opCode, CPUExtension* ext = nullptr)
{
if (ext != nullptr)
return ext->getOpCodeString(opCode);
switch (opCode)
{
case data::OpCodes::NoOp: return "NoOp";
case data::OpCodes::DEBUG_Break: return "debug_break";
case data::OpCodes::BIOSModeImm: return "BIOSModeImm";
case data::OpCodes::MovImmReg: return "MovImmReg";
case data::OpCodes::MovImmMem: return "MovImmMem";
case data::OpCodes::MovRegReg: return "MovRegReg";
@ -347,16 +387,35 @@ namespace dragon
case data::OpCodes::ArgReg: return "ArgReg";
case data::OpCodes::RetInt: return "RetInt";
case data::OpCodes::Int: return "Int";
case data::OpCodes::Ext01: return "Ext01";
case data::OpCodes::Ext02: return "Ext02";
case data::OpCodes::Ext03: return "Ext03";
case data::OpCodes::Ext04: return "Ext04";
case data::OpCodes::Ext05: return "Ext05";
case data::OpCodes::Ext06: return "Ext06";
case data::OpCodes::Ext07: return "Ext07";
case data::OpCodes::Ext08: return "Ext08";
case data::OpCodes::Ext09: return "Ext09";
case data::OpCodes::Ext10: return "Ext10";
case data::OpCodes::Ext11: return "Ext11";
case data::OpCodes::Ext12: return "Ext12";
case data::OpCodes::Ext13: return "Ext13";
case data::OpCodes::Ext14: return "Ext14";
case data::OpCodes::Ext15: return "Ext15";
case data::OpCodes::Ext16: return "Ext16";
default: return "UNKNOWN_INST";
}
}
inline static uint8_t getInstructionSIze(uint8_t opCode)
inline static uint8_t getInstructionSIze(uint8_t opCode, CPUExtension* ext = nullptr)
{
if (ext != nullptr)
return ext->getInstructionSIze(opCode);
switch (opCode)
{
case data::OpCodes::NoOp: return 1;
case data::OpCodes::DEBUG_Break: return 1;
case data::OpCodes::BIOSModeImm: return 2;
case data::OpCodes::MovImmReg: return 4;
case data::OpCodes::MovImmMem: return 5;
case data::OpCodes::MovRegReg: return 3;
@ -425,6 +484,22 @@ namespace dragon
case data::OpCodes::ArgReg: return 2;
case data::OpCodes::RetInt: return 1;
case data::OpCodes::Int: return 2;
case data::OpCodes::Ext01: return 0;
case data::OpCodes::Ext02: return 0;
case data::OpCodes::Ext03: return 0;
case data::OpCodes::Ext04: return 0;
case data::OpCodes::Ext05: return 0;
case data::OpCodes::Ext06: return 0;
case data::OpCodes::Ext07: return 0;
case data::OpCodes::Ext08: return 0;
case data::OpCodes::Ext09: return 0;
case data::OpCodes::Ext10: return 0;
case data::OpCodes::Ext11: return 0;
case data::OpCodes::Ext12: return 0;
case data::OpCodes::Ext13: return 0;
case data::OpCodes::Ext14: return 0;
case data::OpCodes::Ext15: return 0;
case data::OpCodes::Ext16: return 0;
default: return 0;
}
}