From b480537a274ed15d71a59f5babf194a651c78910 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sat, 28 Sep 2024 11:06:36 -0400 Subject: [PATCH] keyboard input buffering --- Makefile | 4 +- circularbuffer.hpp | 573 +++++++++++++++++++++++++++++++++++++++++++++ kernel.cpp | 47 ++-- keyboard.cpp | 44 ++-- keyboard.hpp | 25 ++ memory.cpp | 9 + memory.hpp | 31 +++ 7 files changed, 681 insertions(+), 52 deletions(-) create mode 100644 circularbuffer.hpp diff --git a/Makefile b/Makefile index f3674a6..0480943 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -CXXFLAGS := -m32 -ggdb -g3 -O0 -fno-pic -ffreestanding -fno-rtti -fno-exceptions -std=c++23 -LDFLAGS := -m32 -static -T link.ld -ffreestanding -nostdlib +CXXFLAGS := -m32 -ggdb -g3 -O0 -fno-pic -fno-rtti -fno-exceptions -std=c++23 +LDFLAGS := $(CXXFLAGS) -T link.ld -static -nostdlib -fno-use-cxa-atexit CXXFILES := acpi.cpp \ boot.cpp \ diff --git a/circularbuffer.hpp b/circularbuffer.hpp new file mode 100644 index 0000000..64a9e48 --- /dev/null +++ b/circularbuffer.hpp @@ -0,0 +1,573 @@ +/* +MIT License + +Copyright (c) 2020 Vinit James + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef CIRCULAR_BUFFER_H +#define CIRCULAR_BUFFER_H + +#include +#include +#include +#include +#include +#include + + +template +class CircularBuffer { +private: + + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + template struct BufferIterator; + + +public: + typedef T value_type; + + // clyne + constexpr CircularBuffer() + :_buff{}, _max_size{0} {} + + explicit CircularBuffer(size_t size) + :_buff{std::unique_ptr(new value_type[size])}, _max_size{size}{} + + CircularBuffer(const CircularBuffer& other) + :_buff{std::unique_ptr(new value_type[other._max_size])}, + _max_size{other._max_size}, + _size{other._size}, + _head{other._head}, + _tail{other._tail}{ + std::copy(other.data(), other.data() + _max_size, _buff.get()); + } + + + CircularBuffer& operator=(const CircularBuffer& other){ + if ( this != &other){ + _buff.reset(new value_type[other._max_size]); + _max_size = other._max_size; + _size = other._size; + _head = other._head; + _tail = other._tail; + std::copy(other.data(), other.data() + _max_size, _buff.get()); + } + return *this; + } + + CircularBuffer(CircularBuffer&& other) noexcept + :_buff{std::move(other._buff)}, + _max_size{other._max_size}, + _size{other._size}, + _head{other._head}, + _tail{other._tail}{ + + other._buff = nullptr; + other._max_size = 0; + other._size = 0; + other._head = 0; + other._tail = 0; + } + + + CircularBuffer& operator=(CircularBuffer&& other) noexcept{ + if ( this != &other){ + _buff = std::move(other._buff); + _max_size = other._max_size; + _size = other._size; + _head = other._head; + _tail = other._tail; + + other._buff = nullptr; + other._max_size = 0; + other._size = 0; + other._head = 0; + other._tail = 0; + } + return *this; + } + + void push_back(const value_type& data); + void push_back(value_type&& data) noexcept; + void pop_front(); + reference front(); + reference back(); + const_reference front() const; + const_reference back() const; + void clear(); + bool empty() const ; + bool full() const ; + size_type capacity() const ; + size_type size() const; + size_type buffer_size() const {return sizeof(value_type)*_max_size;}; + const_pointer data() const { return _buff.get(); } + + const_reference operator[](size_type index) const; + reference operator[](size_type index); + const_reference at(size_type index) const; + reference at(size_type index); + + typedef BufferIterator iterator; + typedef BufferIterator const_iterator; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + iterator rbegin() noexcept; + const_iterator rbegin() const noexcept; + iterator rend() noexcept; + const_iterator rend() const noexcept; + + +private: + void _increment_bufferstate(); + void _decrement_bufferstate(); + // clyne + //mutable std::mutex _mtx; + std::unique_ptr _buff; + size_type _head = 0; + size_type _tail = 0; + size_type _size = 0; + size_type _max_size = 0; + + template + struct BufferIterator{ + public: + friend class CircularBuffer; + typedef std::random_access_iterator_tag iterator_category; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef typename std::conditional::type reference; + typedef typename std::conditional::type pointer; + typedef typename std::conditional*, + CircularBuffer*>::type cbuf_pointer; + private: + cbuf_pointer _ptrToBuffer; + size_type _offset; + size_type _index; + bool _reverse; + + bool _comparable(const BufferIterator& other) const{ + return (_ptrToBuffer == other._ptrToBuffer)&&(_reverse == other._reverse); + } + + public: + BufferIterator() + :_ptrToBuffer{nullptr}, _offset{0}, _index{0}, _reverse{false}{} + + BufferIterator(const BufferIterator& it) + :_ptrToBuffer{it._ptrToBuffer}, + _offset{it._offset}, + _index{it._index}, + _reverse{it._reverse}{} + + reference operator*(){ + if(_reverse) + return (*_ptrToBuffer)[(_ptrToBuffer->size() - _index - 1)]; + return (*_ptrToBuffer)[_index]; + } + + pointer operator->() { return &(operator*()); } + + reference operator[](size_type index){ + BufferIterator iter = *this; + iter._index += index; + return *iter; + } + + BufferIterator& operator++(){ + ++_index; + return *this; + } + + BufferIterator operator++(int){ + BufferIterator iter = *this; + ++_index; + return iter; + } + + BufferIterator& operator--(){ + --_index; + return *this; + } + + BufferIterator operator--(int){ + BufferIterator iter = *this; + --_index; + return iter; + } + + friend BufferIterator operator+(BufferIterator lhsiter, difference_type n){ + lhsiter._index += n; + return lhsiter; + } + + friend BufferIterator operator+(difference_type n, BufferIterator rhsiter){ + rhsiter._index += n; + return rhsiter; + } + + + BufferIterator& operator+=(difference_type n){ + _index += n; + return *this; + } + + friend BufferIterator operator-(BufferIterator lhsiter, difference_type n){ + lhsiter._index -= n; + return lhsiter; + } + + friend difference_type operator-(const BufferIterator& lhsiter, const BufferIterator& rhsiter){ + + return lhsiter._index - rhsiter._index; + } + + BufferIterator& operator-=(difference_type n){ + _index -= n; + return *this; + } + + bool operator==(const BufferIterator& other) const{ + if (!_comparable(other)) + return false; + return ((_index == other._index)&&(_offset == other._offset)); + } + + bool operator!=(const BufferIterator& other) const{ + if (!_comparable(other)) + return true; + return ((_index != other._index)||(_offset != other._offset)); + } + + bool operator<(const BufferIterator& other) const { + if (!_comparable(other)) + return false; + return ((_index + _offset)<(other._index+other._offset)); + } + + bool operator>(const BufferIterator& other) const{ + if (!_comparable(other)) + return false; + return ((_index + _offset)>(other._index+other._offset)); + } + + bool operator<=(const BufferIterator& other) const { + if (!_comparable(other)) + return false; + return ((_index + _offset)<=(other._index+other._offset)); + } + + bool operator>=(const BufferIterator& other) const { + if (!_comparable(other)) + return false; + return ((_index + _offset)>=(other._index+other._offset)); + } + }; +}; + +template +inline +bool CircularBuffer::full() const{ + return _size == _max_size; +} + +template +inline +bool CircularBuffer::empty() const{ + return _size == 0; +} + +template +inline +typename CircularBuffer::size_type CircularBuffer::capacity() const{ + return _max_size; +} + +template +inline +void CircularBuffer::clear(){ + //std::lock_guard _lck(_mtx); + _head = _tail = _size = 0; +} + +template +inline +typename CircularBuffer::size_type CircularBuffer::size() const{ + //std::lock_guard _lck(_mtx); + return _size; + } + +template +inline +typename CircularBuffer::reference CircularBuffer::front() { + //std::lock_guard _lck(_mtx); + // clyne + if(empty()) + abort(); //throw std::length_error("front function called on empty buffer"); + return _buff[_tail]; +} + +template +inline +typename CircularBuffer::reference CircularBuffer::back() { + //std::lock_guard _lck(_mtx); + if(empty()) + abort(); //throw std::length_error("back function called on empty buffer"); + return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1]; +} + +template +inline +typename CircularBuffer::const_reference CircularBuffer::front() const{ + //std::lock_guard _lck(_mtx); + if(empty()) + abort(); //throw std::length_error("front function called on empty buffer"); + return _buff[_tail]; +} + +template +inline +typename CircularBuffer::const_reference CircularBuffer::back() const{ + //std::lock_guard _lck(_mtx); + if(empty()) + abort(); //throw std::length_error("back function called on empty buffer"); + return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1]; +} + +template +inline +void CircularBuffer::push_back(const T& data){ + //std::lock_guard _lck(_mtx); + //if(full()) + // _buff[_tail].~T(); + _buff[_head] = data; + _increment_bufferstate(); +} + +template +inline +void CircularBuffer::push_back(T&& data) noexcept{ + //std::lock_guard _lck(_mtx); + _buff[_head] = std::move(data); + _increment_bufferstate(); +} + + +template +inline +void CircularBuffer::_increment_bufferstate(){ + if(full()) + _tail = (_tail + 1)%_max_size; + else + ++_size; + _head = (_head + 1)%_max_size; +} + +template +inline +void CircularBuffer::pop_front(){ + //std::lock_guard _lck(_mtx); + if(empty()) + abort(); //throw std::length_error("pop_front called on empty buffer"); + _decrement_bufferstate(); +} + +template +inline +void CircularBuffer::_decrement_bufferstate(){ + --_size; + _tail = (_tail + 1)%_max_size; +} + +template +inline +typename CircularBuffer::reference CircularBuffer::operator[](size_t index) { + //std::lock_guard _lck(_mtx); + if((index<0)||(index>=_size)) + abort(); //throw std::out_of_range("Index is out of Range of buffer size"); + index += _tail; + index %= _max_size; + return _buff[index]; +} + +template +inline +typename CircularBuffer::const_reference CircularBuffer::operator[](size_t index) const { + //std::lock_guard _lck(_mtx); + if((index<0)||(index>=_size)) + abort(); //throw std::out_of_range("Index is out of Range of buffer size"); + index += _tail; + index %= _max_size; + return _buff[index]; +} + +template +inline +typename CircularBuffer::reference CircularBuffer::at(size_t index) { + //std::lock_guard _lck(_mtx); + if((index<0)||(index>=_size)) + abort(); //throw std::out_of_range("Index is out of Range of buffer size"); + index += _tail; + index %= _max_size; + return _buff[index]; +} + +template +inline +typename CircularBuffer::const_reference CircularBuffer::at(size_t index) const { + //std::lock_guard _lck(_mtx); + if((index<0)||(index>=_size)) + abort(); //throw std::out_of_range("Index is out of Range of buffer size"); + index += _tail; + index %= _max_size; + return _buff[index]; +} + +template +inline +typename CircularBuffer::iterator CircularBuffer::begin() { + //std::lock_guard _lck(_mtx); + iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::begin() const{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::iterator CircularBuffer::end() { + //std::lock_guard _lck(_mtx); + iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::end() const{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::cbegin() const noexcept{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::cend() const noexcept{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::iterator CircularBuffer::rbegin() noexcept{ + //std::lock_guard _lck(_mtx); + iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = true; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::rbegin() const noexcept{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = true; + return iter; +} + +template +inline +typename CircularBuffer::iterator CircularBuffer::rend() noexcept{ + //std::lock_guard _lck(_mtx); + iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = true; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::rend() const noexcept{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = true; + return iter; +} + +#endif /* CIRCULAR_BUFFER_H */ diff --git a/kernel.cpp b/kernel.cpp index 26d5b7d..408a19e 100644 --- a/kernel.cpp +++ b/kernel.cpp @@ -40,35 +40,28 @@ void kernel_main(void) tasking_initialize(); term.write("Tasking enabled.\n"); - //tasking_spawn([] { - // for (;;) { - // do pit_delay_ms(1); - // while (termBusy); - - // termBusy = true; - // term.write('B'); - // termBusy = false; - // } - //}, 256); - - //tasking_spawn([] { - // for (;;) { - // do pit_delay_ms(1); - // while (termBusy); - - // termBusy = true; - // term.write('C'); - // termBusy = false; - // } - //}, 256); - for (;;) { - pit_delay_ms(100); - //while (termBusy); + const auto ch = keyboard_read(); + if (ch) + term.write(*ch); - //termBusy = true; - //term.write('A'); - //termBusy = false; + pit_delay_ms(10); } } +extern "C" +void abort() +{ + term.write("!!! abort() called !!!"); + asm volatile("cli"); + for (;;); +} + +extern "C" +int __cxa_atexit(void (*func)(void *), void *arg, void *dso_handle) +{ + return 0; +} + +int __dso_handle = 0; + diff --git a/keyboard.cpp b/keyboard.cpp index 18d7acd..29178f9 100644 --- a/keyboard.cpp +++ b/keyboard.cpp @@ -1,33 +1,16 @@ +#include "circularbuffer.hpp" #include "idt.hpp" +#include "keyboard.hpp" #include "portio.hpp" #include "vgaterminal.hpp" #include #include -#define K_CONTROL_L -1 -#define K_SHIFT_L -2 -#define K_ALT_L -3 -#define K_CAPS -4 -#define K_NUM -5 -#define K_SCROLL -6 -#define K_SHIFT_R -7 -#define K_ESCAPE -8 -#define K_F1 -10 -#define K_F2 -11 -#define K_F3 -12 -#define K_F4 -13 -#define K_F5 -14 -#define K_F6 -15 -#define K_F7 -16 -#define K_F8 -17 -#define K_F9 -18 -#define K_F10 -19 -#define K_F11 -20 -#define K_F12 -21 - extern TextOutput& term; +static CircularBuffer keyboardBuffer; + static const std::array ScanCodeSet1 {{ 0, K_ESCAPE, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', @@ -52,14 +35,29 @@ static constexpr auto keycode(auto ch) { void keyboard_initialize() { + keyboardBuffer = CircularBuffer(128); + idt_register_callback(33, [](auto& regs) { const auto kc = inb(0x60); if (!isReleased(kc)) { const auto ch = ScanCodeSet1[keycode(kc)]; - if (ch > 0) - term.write(ch); + //if (ch > 0) + // term.write(ch); + + keyboardBuffer.push_back(ch); } }); } +std::optional keyboard_read() +{ + if (keyboardBuffer.empty()) { + return {}; + } else { + const auto ch = keyboardBuffer.front(); + keyboardBuffer.pop_front(); + return ch; + } +} + diff --git a/keyboard.hpp b/keyboard.hpp index 40b57c9..694ff89 100644 --- a/keyboard.hpp +++ b/keyboard.hpp @@ -1,7 +1,32 @@ #ifndef KEYBOARD_HPP #define KEYBOARD_HPP +#include + +#define K_CONTROL_L -1 +#define K_SHIFT_L -2 +#define K_ALT_L -3 +#define K_CAPS -4 +#define K_NUM -5 +#define K_SCROLL -6 +#define K_SHIFT_R -7 +#define K_ESCAPE -8 +#define K_F1 -10 +#define K_F2 -11 +#define K_F3 -12 +#define K_F4 -13 +#define K_F5 -14 +#define K_F6 -15 +#define K_F7 -16 +#define K_F8 -17 +#define K_F9 -18 +#define K_F10 -19 +#define K_F11 -20 +#define K_F12 -21 + void keyboard_initialize(); +std::optional keyboard_read(); + #endif // KEYBOARD_HPP diff --git a/memory.cpp b/memory.cpp index 2cc15be..59e2bbe 100644 --- a/memory.cpp +++ b/memory.cpp @@ -85,3 +85,12 @@ void *operator new[](std::size_t size) return memory_alloc(size); } +void operator delete(void *ptr) +{ + +} + +void operator delete[](void *ptr) +{ + +} diff --git a/memory.hpp b/memory.hpp index 8955262..0467bf6 100644 --- a/memory.hpp +++ b/memory.hpp @@ -1,6 +1,37 @@ #ifndef MEMORY_HPP #define MEMORY_HPP +#include +#include + +template +struct kallocator +{ + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::true_type; + + template + struct rebind { + typedef kallocator other; + }; + + kallocator() = default; + + template + kallocator(const kallocator&) noexcept {} + + T* allocate(std::size_t n) { + return new T[n]; + } + + void deallocate([[maybe_unused]] T* p, [[maybe_unused]] std::size_t n) { + + } +}; + void memory_initialize(); #endif // MEMORY_HPP