mouse support that requires polling
This commit is contained in:
parent
e0f6dd5240
commit
49a9938333
3
400.mu
3
400.mu
|
@ -12,6 +12,9 @@ sig read-key kbd: (addr keyboard) -> _/eax: byte
|
|||
sig load-first-sector-from-primary-bus-secondary-drive out: (addr stream byte)
|
||||
sig store-first-sector-to-primary-bus-secondary-drive out: (addr stream byte)
|
||||
|
||||
# mouse
|
||||
sig read-mouse-event -> _/eax: int, _/ecx: int
|
||||
|
||||
# tests
|
||||
sig count-test-failure
|
||||
sig num-test-failures -> _/eax: int
|
||||
|
|
24
README.md
24
README.md
|
@ -100,24 +100,24 @@ $ ./translate_emulated ex2.mu # ~2 mins to emit disk.img
|
|||
Mu programs can be written for two very different environments:
|
||||
|
||||
* At the top-level, Mu programs emit a bootable image that runs without an OS
|
||||
(under emulation; I haven't tested on native hardware yet). There's just a
|
||||
screen and a keyboard, and that's it. No mouse, no hardware acceleration, no
|
||||
virtual memory, no process separation, no multi-tasking, no persistent
|
||||
storage, no network. All tests run on boot. `main` only runs if all tests
|
||||
pass.
|
||||
(under emulation; I haven't tested on native hardware yet). There's rudimentary
|
||||
support for some core peripherals: a 1024x768 screen, a keyboard with some
|
||||
key-combinations, a PS/2 mouse that must be polled, a slow ATA disk drive.
|
||||
No hardware acceleration, no virtual memory, no process separation, no
|
||||
multi-tasking, no network. Boot always runs all tests, and only gets to
|
||||
`main` if all tests pass.
|
||||
|
||||
* The top-level is built using tools created under the `linux/` sub-directory.
|
||||
This sub-directory contains an entirely separate set of standard libraries
|
||||
intended for building programs that run with just a Linux kernel, reading
|
||||
from stdin and writing to stdout. The Mu compiler is such a program, at
|
||||
`linux/mu.subx`. Individual programs typically run tests if given some
|
||||
commandline argument like `test`.
|
||||
This sub-directory contains an entirely separate set of libraries intended
|
||||
for building programs that run with just a Linux kernel, reading from stdin
|
||||
and writing to stdout. The Mu compiler is such a program, at `linux/mu.subx`.
|
||||
Individual programs typically run tests if given some commandline argument
|
||||
like `test`.
|
||||
|
||||
While I currently focus on programs without an OS, the `linux/` sub-directory
|
||||
is fairly ergonomic. There's a couple of dozen example programs to try out
|
||||
there. It is likely to be the option for a network stack in the foreseeable
|
||||
future; I have no idea how to write to disk or interact on the network without
|
||||
Linux.
|
||||
future; I have no idea how to interact on the network without Linux.
|
||||
|
||||
## Syntax
|
||||
|
||||
|
|
2
bochsrc
2
bochsrc
|
@ -11,5 +11,5 @@ display_library: sdl2
|
|||
|
||||
ata0-master: type=disk, path="disk.img", mode=flat, cylinders=20, heads=16, spt=63 # 10MB, 512 bytes per sector
|
||||
boot: disk
|
||||
# PS/2 mouse requires black magic that I don't know how to explain.
|
||||
mouse: enabled=1, toggle=ctrl+f10
|
||||
log: -
|
||||
|
|
215
boot.subx
215
boot.subx
|
@ -219,6 +219,8 @@ initialize_32bit_mode:
|
|||
|
||||
fb/enable-interrupts
|
||||
|
||||
(initialize-mouse)
|
||||
|
||||
## enable floating point
|
||||
db/floating-point-coprocessor e3/initialize
|
||||
# eax <- cr4
|
||||
|
@ -805,14 +807,15 @@ Font:
|
|||
|
||||
== code
|
||||
|
||||
# Use 28-bit PIO mode to read the first sector (512 bytes) from an IDE (ATA)
|
||||
# disk drive.
|
||||
## Controlling IDE (ATA) hard disks
|
||||
# Uses 28-bit PIO mode.
|
||||
# Inspired by https://colorforth.github.io/ide.html
|
||||
#
|
||||
# Resources:
|
||||
# https://wiki.osdev.org/ATA_PIO_Mode
|
||||
# https://forum.osdev.org/viewtopic.php?f=1&p=167798
|
||||
# read-sector, according to https://www.scs.stanford.edu/11wi-cs140/pintos/specs/ata-3-std.pdf
|
||||
|
||||
load-first-sector-from-primary-bus-secondary-drive: # out: (addr stream byte)
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
|
@ -1183,4 +1186,212 @@ until-ata-ready-for-data:
|
|||
(until-ata-data-available)
|
||||
c3/return
|
||||
|
||||
## Controlling a PS/2 mouse
|
||||
# Uses no IRQs, just polling.
|
||||
# Thanks Dave Long: https://github.com/jtauber/cleese/blob/master/necco/kernel/bochs/py8042.py
|
||||
#
|
||||
# Resources:
|
||||
# https://wiki.osdev.org/Mouse_Input
|
||||
|
||||
# results x/eax, y/ecx range from -256 to +255
|
||||
# See https://wiki.osdev.org/index.php?title=Mouse_Input&oldid=25663#Format_of_First_3_Packet_Bytes
|
||||
read-mouse-event: # -> _/eax: int, _/ecx: int
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
52/push-edx
|
||||
53/push-ebx
|
||||
# if no event, return 0, 0
|
||||
b8/copy-to-eax 0/imm32
|
||||
b9/copy-to-ecx 0/imm32
|
||||
(any-mouse-event?) # => eax
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= $read-mouse-event:end/disp8
|
||||
# var f1/edx: byte = inb(0x60)
|
||||
31/xor %eax 0/r32/eax
|
||||
e4/read-port-into-al 0x60/imm8
|
||||
89/<- %edx 0/r32/eax
|
||||
(wait-for-mouse-event)
|
||||
# var dx/ebx: byte = inb(0x60)
|
||||
31/xor %eax 0/r32/eax
|
||||
e4/read-port-into-al 0x60/imm8
|
||||
89/<- %ebx 0/r32/eax
|
||||
(wait-for-mouse-event)
|
||||
# var dy/ecx: byte = inb(0x60)
|
||||
31/xor %eax 0/r32/eax
|
||||
e4/read-port-into-al 0x60/imm8
|
||||
89/<- %ecx 0/r32/eax
|
||||
# eax = dx
|
||||
89/<- %eax 3/r32/ebx
|
||||
# if (f1 & 0x10) dx = -dx
|
||||
{
|
||||
f6 0/subop/test-bits %dl 0x10/imm8
|
||||
74/jump-if-zero break/disp8
|
||||
0d/or-eax-with 0xffffff00/imm32
|
||||
}
|
||||
# if (f1 & 0x20) dy = -dy
|
||||
{
|
||||
f6 0/subop/test-bits %dl 0x20/imm8
|
||||
74/jump-if-zero break/disp8
|
||||
81 1/subop/or %ecx 0xffffff00/imm32
|
||||
}
|
||||
$read-mouse-event:end:
|
||||
# . restore registers
|
||||
5b/pop-to-ebx
|
||||
5a/pop-to-edx
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
wait-for-mouse-event:
|
||||
# . save registers
|
||||
50/push-eax
|
||||
#
|
||||
{
|
||||
(any-mouse-event?) # => eax
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= loop/disp8
|
||||
}
|
||||
$wait-for-mouse-event:end:
|
||||
# . restore registers
|
||||
58/pop-to-eax
|
||||
# .
|
||||
c3/return
|
||||
|
||||
any-mouse-event?: # -> _/eax: boolean
|
||||
31/xor %eax 0/r32/eax
|
||||
# 0x1 bit: there's data from the keyboard controller
|
||||
# 0x20 bit: it's data from the aux port (the mouse)
|
||||
e4/read-port-into-al 0x60/imm8
|
||||
24/and-al-with 0x21/imm8
|
||||
3c/compare-al-with 0x21/imm8
|
||||
0f 94/set-byte-if-= %al
|
||||
c3/return
|
||||
|
||||
initialize-mouse:
|
||||
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "A" 7 0)
|
||||
(enable-keyboard-controller-aux-device)
|
||||
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "B" 7 0)
|
||||
# tell mouse to use default settings
|
||||
(send-mouse-command 0xf6)
|
||||
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "P" 7 0)
|
||||
# enable mouse
|
||||
(send-mouse-command 0xf4)
|
||||
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "Z" 7 0)
|
||||
c3/return
|
||||
|
||||
enable-keyboard-controller-aux-device:
|
||||
(command-keyboard-controller 0xa8)
|
||||
c3/return
|
||||
|
||||
send-mouse-command: # command: byte
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
#
|
||||
(command-keyboard-controller 0xd4)
|
||||
(send-keyboard-controller-data *(ebp+8))
|
||||
(wait-for-ack-from-mouse)
|
||||
$send-mouse-command:end:
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
wait-for-ack-from-mouse:
|
||||
# . save registers
|
||||
50/push-eax
|
||||
{
|
||||
(read-keyboard-controller-data) # => eax
|
||||
(draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %eax 7 0) # screen n fg bg
|
||||
81 7/subop/compare %eax 0xfa/imm32
|
||||
75/jump-if-!= loop/disp8
|
||||
}
|
||||
$wait-for-ack-from-mouse:end:
|
||||
# . restore registers
|
||||
58/pop-eax
|
||||
c3/return
|
||||
|
||||
command-keyboard-controller: # command: byte
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
50/push-eax
|
||||
#
|
||||
(poll-keyboard-controller-to-write)
|
||||
8b/-> *(ebp+8) 0/r32/eax
|
||||
e6/write-al-into-port 0x64/imm8
|
||||
$command-keyboard-controller:end:
|
||||
# . restore registers
|
||||
58/pop-to-eax
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
send-keyboard-controller-data: # data: byte
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
50/push-eax
|
||||
#
|
||||
(poll-keyboard-controller-to-write)
|
||||
8b/-> *(ebp+8) 0/r32/eax
|
||||
e6/write-al-into-port 0x60/imm8
|
||||
$send-keyboard-controller-data:end:
|
||||
# . restore registers
|
||||
58/pop-to-eax
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
read-keyboard-controller-data: # -> _/eax: byte
|
||||
(poll-keyboard-controller-to-read-data-port)
|
||||
31/xor %eax 0/r32/eax
|
||||
e4/read-port-into-al 0x60/imm8
|
||||
c3/return
|
||||
|
||||
poll-keyboard-controller-to-write:
|
||||
# . save registers
|
||||
50/push-eax
|
||||
# "All output to port 0x60 or 0x64 must be preceded by waiting for bit 1
|
||||
# (value=2) of port 0x64 to become clear."
|
||||
# https://wiki.osdev.org/index.php?title=Mouse_Input&oldid=25663#Waiting_to_Send_Bytes_to_Port_0x60_and_0x64
|
||||
{
|
||||
e4/read-port-into-al 0x64/imm8
|
||||
a8/test-bits-in-al 2/imm8 # set zf if bit 1 (second-least significant) is not set
|
||||
75/jump-if-zf-not-set-and-bit-1-set loop/disp8
|
||||
}
|
||||
$poll-keyboard-controller-to-write:end:
|
||||
# . restore registers
|
||||
58/pop-to-eax
|
||||
# . epilogue
|
||||
c3/return
|
||||
|
||||
poll-keyboard-controller-to-read-data-port:
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
50/push-eax
|
||||
# "Bytes cannot be read from port 0x60 until bit 0 (value=1) of port 0x64 is set."
|
||||
# https://wiki.osdev.org/index.php?title=Mouse_Input&oldid=25663#Waiting_to_Send_Bytes_to_Port_0x60_and_0x64
|
||||
{
|
||||
e4/read-port-into-al 0x64/imm8
|
||||
a8/test-bits-in-al 1/imm8 # set zf if bit 0 (least significant) is not set
|
||||
74/jump-if-zf-set-and-bit-0-not-set loop/disp8
|
||||
}
|
||||
$poll-keyboard-controller-to-read-data-port:end:
|
||||
# . restore registers
|
||||
58/pop-to-eax
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
# vim:ft=subx
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# Demo of mouse, showing deltas in x and y position for every event.
|
||||
#
|
||||
# To build a disk image:
|
||||
# ./translate ex10.mu # emits disk.img
|
||||
# To run:
|
||||
# qemu-system-i386 disk.img
|
||||
# Or:
|
||||
# bochs -f bochsrc # bochsrc loads disk.img
|
||||
#
|
||||
# Expected output:
|
||||
# Values between -256 and +255 as you move the mouse over the window.
|
||||
# You might need to click on the window once.
|
||||
|
||||
fn main {
|
||||
# repeatedly print out mouse driver results if non-zero
|
||||
$main:event-loop: {
|
||||
var dx/eax: int <- copy 0
|
||||
var dy/ecx: int <- copy 0
|
||||
dx, dy <- read-mouse-event
|
||||
{
|
||||
compare dx, 0
|
||||
break-if-!=
|
||||
compare dy, 0
|
||||
break-if-!=
|
||||
loop $main:event-loop
|
||||
}
|
||||
{
|
||||
var dummy1/eax: int <- copy 0
|
||||
var dummy2/ecx: int <- copy 0
|
||||
dummy1, dummy2 <- draw-text-wrapping-right-then-down-over-full-screen 0/screen, " ", 0/x, 0x10/y, 0x31/fg, 0/bg
|
||||
}
|
||||
{
|
||||
var dummy/ecx: int <- copy 0
|
||||
dx, dummy <- draw-int32-decimal-wrapping-right-then-down-over-full-screen 0/screen, dx, 0/x, 0x10/y, 0x31/fg, 0/bg
|
||||
}
|
||||
{
|
||||
var dummy/eax: int <- copy 0
|
||||
dummy, dy <- draw-int32-decimal-wrapping-right-then-down-over-full-screen 0/screen, dy, 5/x, 0x10/y, 0x31/fg, 0/bg
|
||||
}
|
||||
loop
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue