starts work on the PIT

This commit is contained in:
2025-06-06 12:47:02 -04:00
parent 3e01dc2074
commit 1e1a28e23d
3 changed files with 247 additions and 0 deletions

27
TODO.md
View File

@ -1,5 +1,32 @@
## What do I need to do? ## What do I need to do?
PS/2 controller
-> need to setup some timing device, probably PIT
-> need to setup the USB controller first, so i can disable Legacy USB bios shit
-> need to configure ACPI so i can actually detect for the PS/2 controller
-> then we can start configuring the PS/2
-> to properly send data to PS/2 controllers, we need some sort of timing interface,
this way we can timeout if we're being hanged on sending commands to a ps/2 device
PIT timer, or some sort of timer interface
perhaps maybe some more things off of the PIC? im not sure
really after that I want to do more to work towards userspace, so that I can start creating things
scheduler?
multi processing? threads?
etc
### Features I want ### Features I want
- A kernel bus - A kernel bus

3
kernel/arch/io/pit.c Normal file
View File

@ -0,0 +1,3 @@
#include <kernel/x86/pit.h>

View File

@ -0,0 +1,217 @@
#ifndef ARCH_PIT_H
#define ARCH_PIT_H
#define PIT_CHANNEL_0 (0x40) // R/W
#define PIT_CHANNEL_1 (0x41) // R/W
#define PIT_CHANNEL_2 (0x42) // R/W
#define PIT_CMD_REG (0x43) // W
/**
* Selects which channel is being configured.
* Must always be valid on every write to the CMD register
*
* READ_BACK isn't always supported
*/
enum PIT_CHANNEL {
CHANNEL_0 = 0x0,
CHANNEL_1,
CHANNEL_2,
READ_BACK // 8254 only
};
/**
* Tells the PIT which access mode to use for the selected channel. (Or counter latch cmd)
* These must be valid on every write to the CMD register.
*
* LOBYTE indicates that only the low 8 bytes of a (16-bit) value will be transmitted to the lower bit of the register
* HIBYTE is the same, but for the higher value
* HI AND LOW means that the values will come sequentially through the IO port, lowest followed by highest
*/
enum PIT_ACCESS_MODE {
LATCH_COUNT_VAL_CMD = 0x0,
LO_BYTE_ONLY,
HI_BYTE_ONLY,
HI_AND_LO_BYTE
};
/**
* While each operating mode functions differently, they all have these in common:
*
* Everytime the cmd register is written to, all interal logic on the selected PIT channel is reset, the output will immediately revert to the mode's initial state
*
* A new reload value can be written to a PIT channel's data port at any time.
*
* The current counter value is always either decremented or reset to the reload value on the *falling* edge of the input signal.
*
* In modes where the current count is decremented when it is reloaded, the current count is not decremented on the same input clock pulse as the reload
* it starts decrementing on the next input clock pulse
*
*/
enum PIT_OPERATING_MODE {
/**
* **MODE 0**
* When the cmd reigster is written, the output signal goes low and the PIT waits for the reload register to be set by software, to begin the countdown.
* After the reload register has been set, the current count will be set to the reload value on the next falling edge of the signal.
* Subsequent falling edges of the input signal will decrement the current count, (if the gate input is high on the preceding rising edge of the input signal).
*
* When the current count decrements from one to zero, the output goes high and remains high until another cmd register is written, or the reload register is set again.
* The current count will wrap around to 0xFFFF (0x9999 in BCD) and continue to decrement until the cmd register or the reload register are set, however this will not affect the output pin state.
*
* The reload value can be changed at any time. In "lobyte/hibyte" access mode counting will stop when the first byte of the reload value is set.
* Once the full reload value is set (in any access mode), the next falling edge of the input signal will cause the new reload value to be copied into the current count,
* and the countdown will continue from the new value.
*
* This mode only generates interrupts on channel zero.
*
*/
MODE_0 = 0x0, // Interrupt on terminal count
/**
* **MODE 1**
* This mode is similar to mode 0, however counting doesn't start until a rising edge of the gate input is detected.
* For this reason it is not usable for PIT channels 0 or 1 (where the gate input can't be changed).
*
* When the CMD register is written, the output signal goes high and the PIT waits for the reload register to be set by software.
* After the reload register has been set, the PIT will wait for the next rising edge of the gate input.
* Once this occurs, the output signal will go low and the current count will be set to the reload value on the next falling edge of the input signal.
* Subsequent falling edges of the input signal will decrement the current count.
*
* When the current count decrements from one to zero, the output goes high and remains high until another cmd register is written or the reload register is set again.
* The current count will wrap around to 0xFFFF (0x9999 in BCD) and continue to decrement until the cmd register or the reload register are set, however this will not affect the output pin state.
*
* If the gate input signal goes low during this process it will have no effect.
* However, if the gate input goes high again it will cause the current count to be reloaded from the reload register on the next falling edge of the input signal,
* and restart the count again (the same as when counting first started).
*
* The reload value can be changed at any time, however the new value will not affect the current count until the current count is reloaded (on the next rising edge of gate input)
* So if you want to do this, clear and then reset bit 0 of IO port 0x61, after modifying the reload value.
*/
MODE_1, // hardware re-triggerable one-shot
/**
* **MODE 2**
* This mode operates as a frequency divider.
*
* When the mode/command register is written the output signal goes high and the PIT waits for the reload register to be set by software. After the reload register has been set, the current count will be set to the reload value on the next falling edge of the (1.193182 MHz) input signal. Subsequent falling edges of the input signal will decrement the current count (if the gate input is high on the preceding rising edge of the input signal).
*
* When the current count decrements from two to one, the output goes low, and on the next falling edge of the (1.193182 MHz) input signal it will go high again and the current count will be set to the reload value and counting will continue.
*
* If the gate input goes low, counting stops and the output goes high immediately. Once the gate input has returned high, the next falling edge on input signal will cause the current count to be set to the reload value and operation will continue.
*
* The reload value can be changed at any time, however the new value will not affect the current count until the current count is reloaded (when it is decreased from two to one, or the gate input going low then high). When this occurs counting will continue using the new reload value.
*
* A reload value (or divisor) of one must not be used with this mode.
*
* This mode creates a high output signal that drops low for one input signal cycle (0.8381 uS), which is too fast to make a difference to the PC speaker (see mode 3). For this reason mode 2 is useless for producing sounds with PIT channel 2.
*
* Typically, OSes and BIOSes use mode 3 (see below) for PIT channel 0 to generate IRQ 0 timer ticks, but some use mode 2 instead, to gain frequency accuracy (frequency = 1193182 / reload_value Hz).
*/
MODE_2, // rate generator
/**
* **MODE 3**
*
* For mode 3, the PIT channel operates as a frequency divider like mode 2,
however the output signal is fed into an internal "flip flop" to produce a square wave (rather than a short pulse).
* The flip flop changes its output state each time its input state (or the output of the PIT channel's frequency divider) changes.
* This causes the actual output to change state half as often, so to compensate for this the current count is decremented twice on each falling edge of the input signal (instead of once),
* and the current count is set to the reload value twice as often.
*
* When the mode/command register is written the output signal goes high and the PIT waits for the reload register to be set by software.
* After the reload register has been set, the current count will be set to the reload value on the next falling edge of the (1.193182 MHz) input signal.
* Subsequent falling edges of the input signal will decrement the current count twice (if the gate input is high on the preceding rising edge of the input signal).
*
* Note: under normal circumstances the output state will be low 50% of the time when the mode/command register is written.
* The output will then go high, which will generate an immediate (perhaps spurious) IRQ0. The other 50% of the time the output will already be high, and there will be no IRQ0 generated.
*
* For even reload values, when the current count decrements from two to zero the output of the flip-flop changes state;
* the current count will be reset to the reload value and counting will continue.
*
* For odd reload values, the current count is always set to one less than the reload value.
* If the output of the flip flop is low when the current count decrements from two to zero it will behave the same as the equivalent even reload value.
* However, if the output of the flip flop is high the reload will be delayed for one input signal cycle (0.8381 uS),
* which causes the "high" pulse to be slightly longer and the duty cycle will not be exactly 50%.
* Because the reload value is rounded down to the nearest even number anyway,
* it is recommended that only even reload values be used (which means you should mask the value before sending it to the port).
*
* Note: This even value limitation on the reload value in mode 3 reduces the number of possible output frequencies in half.
* If you want to be able to control the frequency of IRQ0 to a somewhat higher degree, then think about using mode 2 instead for channel 0.
*
* On channel 2, if the gate input goes low, counting stops and the output goes high immediately.
* Once the gate input has returned high, the next falling edge on input signal will cause the current count to be set to the reload value and operation will continue (with the output left high).
*
* The reload value can be changed at any time, however the new value will not affect the current count until the current count is reloaded
* (when it is decreased from two to zero, or the gate input going low then high). When this occurs counting will continue using the new reload value.
*
* A reload value (or divisor) of one must not be used with this mode.
*/
MODE_3, // square wave generator
/**
* **MODE 4**
*
* Mode four operates as a retriggerable delay, and generates a pulse when the current count reaches zero.
*
* When the mode/command register is written the output signal goes high and the PIT waits for the reload register to be set by software.
* After the reload register has been set, the current count will be set to the reload value on the next falling edge of the (1.193182 MHz) input signal.
* Subsequent falling edges of the input signal will decrement the current count (if the gate input is high on the preceding rising edge of the input signal).
*
* When the current count decrements from one to zero, the output goes low for one cycle of the input signal (0.8381 uS).
* The current count will wrap around to 0xFFFF (or 0x9999 in BCD mode) and continue to decrement until the mode/command register or the reload register are set,
* however this will not affect the output state.
*
* If the gate input goes low, counting stops but the output will not be affected and the current count will not be reset to the reload value.
*
* The reload value can be changed at any time.
* When the new value has been set (both bytes for "lobyte/hibyte" access mode) it will be loaded into the current count on the next falling edge of the (1.193182 MHz) input signal,
* and counting will continue using the new reload value.
*/
MODE_4, // software triggered strobe
/**
* **MODE 5**
* Mode 5 is similar to mode 4, except that it waits for the rising edge of the gate input to trigger (or re-trigger) the delay period (like mode 1).
* For this reason it is not usable for PIT channels 0 or 1 (where the gate input can't be changed).
*
* When the mode/command register is written the output signal goes high and the PIT waits for the reload register to be set by software.
* After the reload register has been set the PIT will wait for the next rising edge of the gate input.
* Once this occurs, the current count will be set to the reload value on the next falling edge of the (1.193182 MHz) input signal.
* Subsequent falling edges of the input signal will decrement the current count.
*
* When the current count decrements from one to zero, the output goes low for one cycle of the input signal (0.8381 uS).
* The current count will wrap around to 0xFFFF (or 0x9999 in BCD mode) and continue to decrement until the mode/command register or the reload register are set,
* however this will not affect the output state.
*
* If the gate input signal goes low during this process it will have no effect.
* However, if the gate input goes high again it will cause the current count to be reloaded from the reload register on the next falling edge of the input signal,
* and restart the count again (the same as when counting first started).
*
* The reload value can be changed at any time, however the new value will not affect the current count until the current count is reloaded (on the next rising edge of the gate input).
* When this occurs counting will continue using the new reload value.
*/
MODE_5, // hardware triggered strobe
_MODE_2, // mode 2
_MODE_3 // mode 3
};
/**
* Binary mode is the standard value,
* where as BCD will hold a single decimal value in each of the four bits
* The counter for BCD goes to 0x9999, instead of 0xFFFF
*
* BCD is not properly implemented on all chips, even if they say they support it.
*/
enum PIT_DIGIT_MODE {
BINARY_MODE = 0x0, // 16-bit binary
BCD_MODE // four-digit bcd
};
#endif