Merge pull request #107 from SamTebbs33/pit-adding-tests
Added run time tests for PIT
This commit is contained in:
commit
e5e8939c3f
5 changed files with 469 additions and 110 deletions
|
@ -240,6 +240,7 @@ test "" {
|
||||||
_ = @import("pic.zig");
|
_ = @import("pic.zig");
|
||||||
_ = @import("isr.zig");
|
_ = @import("isr.zig");
|
||||||
_ = @import("irq.zig");
|
_ = @import("irq.zig");
|
||||||
|
_ = @import("pit.zig");
|
||||||
_ = @import("syscalls.zig");
|
_ = @import("syscalls.zig");
|
||||||
_ = @import("paging.zig");
|
_ = @import("paging.zig");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,70 @@
|
||||||
const arch = @import("arch.zig");
|
const std = @import("std");
|
||||||
const assert = @import("std").debug.assert;
|
const maxInt = std.math.maxInt;
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const is_test = builtin.is_test;
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const expectError = std.testing.expectError;
|
||||||
|
const build_options = @import("build_options");
|
||||||
|
const mock_path = build_options.arch_mock_path;
|
||||||
|
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
|
||||||
|
const panic = if (is_test) @import(mock_path ++ "panic_mock.zig").panic else @import("../../panic.zig").panic;
|
||||||
const irq = @import("irq.zig");
|
const irq = @import("irq.zig");
|
||||||
const pic = @import("pic.zig");
|
const pic = @import("pic.zig");
|
||||||
const log = @import("../../log.zig");
|
const log = @import("../../log.zig");
|
||||||
const panic = @import("../../panic.zig").panic;
|
|
||||||
|
|
||||||
// The port addresses of the PIT registers
|
/// The enum for selecting the counter
|
||||||
|
const CounterSelect = enum {
|
||||||
|
/// Counter 0.
|
||||||
|
Counter0,
|
||||||
|
|
||||||
|
/// Counter 1.
|
||||||
|
Counter1,
|
||||||
|
|
||||||
|
/// Counter 2.
|
||||||
|
Counter2,
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the register port for the selected counter.
|
||||||
|
///
|
||||||
|
/// Arguments:
|
||||||
|
/// IN counter: CounterSelect - The counter to get the register port.
|
||||||
|
///
|
||||||
|
/// Return: u16
|
||||||
|
/// The register port for the selected counter.
|
||||||
|
///
|
||||||
|
pub fn getRegister(counter: CounterSelect) u16 {
|
||||||
|
return switch (counter) {
|
||||||
|
.Counter0 => COUNTER_0_REGISTER,
|
||||||
|
.Counter1 => COUNTER_1_REGISTER,
|
||||||
|
.Counter2 => COUNTER_2_REGISTER,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the operational control work for the selected counter.
|
||||||
|
///
|
||||||
|
/// Arguments:
|
||||||
|
/// IN counter: CounterSelect - The counter to get the operational control work.
|
||||||
|
///
|
||||||
|
/// Return: u16
|
||||||
|
/// The operational control work for the selected counter.
|
||||||
|
///
|
||||||
|
pub fn getCounterOCW(counter: CounterSelect) u8 {
|
||||||
|
return switch (counter) {
|
||||||
|
.Counter0 => OCW_SELECT_COUNTER_0,
|
||||||
|
.Counter1 => OCW_SELECT_COUNTER_1,
|
||||||
|
.Counter2 => OCW_SELECT_COUNTER_2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The error set that can be returned from PIT functions
|
||||||
|
const PitError = error{
|
||||||
|
/// The frequency to be used for a counter is invalid. This would be if the frequency is less
|
||||||
|
/// than 19 or greater than MAX_FREQUENCY.
|
||||||
|
InvalidFrequency,
|
||||||
|
};
|
||||||
|
|
||||||
/// The port address for the PIT data register for counter 0. This is going to be used as the
|
/// The port address for the PIT data register for counter 0. This is going to be used as the
|
||||||
/// system clock.
|
/// system clock.
|
||||||
|
@ -23,7 +82,7 @@ const COUNTER_2_REGISTER: u16 = 0x42;
|
||||||
/// about to happen. Tell what data is going where, lower or upper part of it's registers.
|
/// about to happen. Tell what data is going where, lower or upper part of it's registers.
|
||||||
const COMMAND_REGISTER: u16 = 0x43;
|
const COMMAND_REGISTER: u16 = 0x43;
|
||||||
|
|
||||||
// The operational command word marks for the different modes.
|
// The operational command word for the different modes.
|
||||||
//
|
//
|
||||||
// Bit 0: (BCP) Binary Counter.
|
// Bit 0: (BCP) Binary Counter.
|
||||||
// 0: Binary.
|
// 0: Binary.
|
||||||
|
@ -49,65 +108,65 @@ const COMMAND_REGISTER: u16 = 0x43;
|
||||||
// 11: Illegal value.
|
// 11: Illegal value.
|
||||||
|
|
||||||
/// Have the counter count in binary (internally?).
|
/// Have the counter count in binary (internally?).
|
||||||
const OCW_BINARY_COUNT_BINARY: u8 = 0x00; // xxxxxxx0
|
const OCW_BINARY_COUNT_BINARY: u8 = 0x00;
|
||||||
|
|
||||||
/// Have the counter count in BCD (internally?).
|
/// Have the counter count in BCD (internally?).
|
||||||
const OCW_BINARY_COUNT_BCD: u8 = 0x01; // xxxxxxx1
|
const OCW_BINARY_COUNT_BCD: u8 = 0x01;
|
||||||
|
|
||||||
/// The PIT counter will be programmed with an initial COUNT value that counts down at a rate of
|
/// The PIT counter will be programmed with an initial COUNT value that counts down at a rate of
|
||||||
/// the input clock frequency. When the COUNT reaches 0, and after the control word is written,
|
/// the input clock frequency. When the COUNT reaches 0, and after the control word is written,
|
||||||
/// then its OUT pit is set high (1). Count down starts then the COUNT is set. The OUT pin remains
|
/// then its OUT pit is set high (1). Count down starts then the COUNT is set. The OUT pin remains
|
||||||
/// high until the counter is reloaded with a new COUNT value or a new control work is written.
|
/// high until the counter is reloaded with a new COUNT value or a new control work is written.
|
||||||
const OCW_MODE_TERMINAL_COUNT: u8 = 0x00; // xxxx000x
|
const OCW_MODE_TERMINAL_COUNT: u8 = 0x00;
|
||||||
|
|
||||||
/// The counter is programmed to output a pulse every curtain number of clock pulses. The OUT pin
|
/// The counter is programmed to output a pulse every curtain number of clock pulses. The OUT pin
|
||||||
/// remains high as soon as a control word is written. When COUNT is written, the counter waits
|
/// remains high as soon as a control word is written. When COUNT is written, the counter waits
|
||||||
/// until the rising edge of the GATE pin to start. One clock pulse after the GATE pin, the OUT
|
/// until the rising edge of the GATE pin to start. One clock pulse after the GATE pin, the OUT
|
||||||
/// pin will remain low until COUNT reaches 0.
|
/// pin will remain low until COUNT reaches 0.
|
||||||
const OCW_MODE_ONE_SHOT: u8 = 0x02; // xxxx001x
|
const OCW_MODE_ONE_SHOT: u8 = 0x02;
|
||||||
|
|
||||||
/// The counter is initiated with a COUNT value. Counting starts next clock pulse. OUT pin remains
|
/// The counter is initiated with a COUNT value. Counting starts next clock pulse. OUT pin remains
|
||||||
/// high until COUNT reaches 1, then is set low for one clock pulse. Then COUNT is reset back to
|
/// high until COUNT reaches 1, then is set low for one clock pulse. Then COUNT is reset back to
|
||||||
/// initial value and OUT pin is set high again.
|
/// initial value and OUT pin is set high again.
|
||||||
const OCW_MODE_RATE_GENERATOR: u8 = 0x04; // xxxx010x
|
const OCW_MODE_RATE_GENERATOR: u8 = 0x04;
|
||||||
|
|
||||||
/// Similar to PIT_OCW_MODE_RATE_GENERATOR, but OUT pin will be high for half the time and low for
|
/// Similar to PIT_OCW_MODE_RATE_GENERATOR, but OUT pin will be high for half the time and low for
|
||||||
/// half the time. Good for the speaker when setting a tone.
|
/// half the time. Good for the speaker when setting a tone.
|
||||||
const OCW_MODE_SQUARE_WAVE_GENERATOR: u8 = 0x06; // xxxx011x
|
const OCW_MODE_SQUARE_WAVE_GENERATOR: u8 = 0x06;
|
||||||
|
|
||||||
/// The counter is initiated with a COUNT value. Counting starts on next clock pulse. OUT pin remains
|
/// The counter is initiated with a COUNT value. Counting starts on next clock pulse. OUT pin remains
|
||||||
/// high until count is 0. Then OUT pin is low for one clock pulse. Then resets to high again.
|
/// high until count is 0. Then OUT pin is low for one clock pulse. Then resets to high again.
|
||||||
const OCW_MODE_SOFTWARE_TRIGGER: u8 = 0x08; // xxxx100x
|
const OCW_MODE_SOFTWARE_TRIGGER: u8 = 0x08;
|
||||||
|
|
||||||
/// The counter is initiated with a COUNT value. OUT pin remains high until the rising edge of the
|
/// The counter is initiated with a COUNT value. OUT pin remains high until the rising edge of the
|
||||||
/// GATE pin. Then the counting begins. When COUNT reaches 0, OUT pin goes low for one clock pulse.
|
/// GATE pin. Then the counting begins. When COUNT reaches 0, OUT pin goes low for one clock pulse.
|
||||||
/// Then COUNT is reset and OUT pin goes high. This cycles for each rising edge of the GATE pin.
|
/// Then COUNT is reset and OUT pin goes high. This cycles for each rising edge of the GATE pin.
|
||||||
const OCW_MODE_HARDWARE_TRIGGER: u8 = 0x0A; // xxxx101x
|
const OCW_MODE_HARDWARE_TRIGGER: u8 = 0x0A;
|
||||||
|
|
||||||
/// The counter value is latched into an internal control register at the time of the I/O write
|
/// The counter value is latched into an internal control register at the time of the I/O write
|
||||||
/// operations.
|
/// operations.
|
||||||
const OCW_READ_LOAD_LATCH: u8 = 0x00; // xx00xxxx
|
const OCW_READ_LOAD_LATCH: u8 = 0x00;
|
||||||
|
|
||||||
/// Read or load the most significant bit only.
|
/// Read or load the most significant bit only.
|
||||||
const OCW_READ_LOAD_LSB_ONLY: u8 = 0x10; // xx01xxxx
|
const OCW_READ_LOAD_LSB_ONLY: u8 = 0x10;
|
||||||
|
|
||||||
/// Read or load the least significant bit only.
|
/// Read or load the least significant bit only.
|
||||||
const OCW_READ_LOAD_MSB_ONLY: u8 = 0x20; // xx10xxxx
|
const OCW_READ_LOAD_MSB_ONLY: u8 = 0x20;
|
||||||
|
|
||||||
/// Read or load the least significant bit first then the most significant bit.
|
/// Read or load the least significant bit first then the most significant bit.
|
||||||
const OCW_READ_LOAD_DATA: u8 = 0x30; // xx11xxxx
|
const OCW_READ_LOAD_DATA: u8 = 0x30;
|
||||||
|
|
||||||
/// The OCW bits for selecting counter 0. Used for the system clock.
|
/// The OCW bits for selecting counter 0. Used for the system clock.
|
||||||
const OCW_SELECT_COUNTER_0: u8 = 0x00; // 00xxxxxx
|
const OCW_SELECT_COUNTER_0: u8 = 0x00;
|
||||||
|
|
||||||
/// The OCW bits for selecting counter 1. Was for the memory refreshing.
|
/// The OCW bits for selecting counter 1. Was for the memory refreshing.
|
||||||
const OCW_SELECT_COUNTER_1: u8 = 0x40; // 01xxxxxx
|
const OCW_SELECT_COUNTER_1: u8 = 0x40;
|
||||||
|
|
||||||
/// The OCW bits for selecting counter 2. Channel for the speaker.
|
/// The OCW bits for selecting counter 2. Channel for the speaker.
|
||||||
const OCW_SELECT_COUNTER_2: u8 = 0x80; // 10xxxxxx
|
const OCW_SELECT_COUNTER_2: u8 = 0x80;
|
||||||
|
|
||||||
// The divisor constant
|
/// The divisor constant
|
||||||
const MAX_FREQUENCY: u32 = 1193180;
|
const MAX_FREQUENCY: u32 = 1193182;
|
||||||
|
|
||||||
/// The number of ticks that has passed when counter 0 was initially set up.
|
/// The number of ticks that has passed when counter 0 was initially set up.
|
||||||
var ticks: u32 = 0;
|
var ticks: u32 = 0;
|
||||||
|
@ -118,17 +177,20 @@ var ram_ticks: u32 = 0;
|
||||||
/// The number of tick that has passed when counter 2 was initially set up.
|
/// The number of tick that has passed when counter 2 was initially set up.
|
||||||
var speaker_ticks: u32 = 0;
|
var speaker_ticks: u32 = 0;
|
||||||
|
|
||||||
// The current frequency of counter 0
|
/// The current frequency of counter 0
|
||||||
var current_freq_0: u32 = undefined;
|
var current_freq_0: u32 = undefined;
|
||||||
|
|
||||||
// The current frequency of counter 1
|
/// The current frequency of counter 1
|
||||||
var current_freq_1: u32 = undefined;
|
var current_freq_1: u32 = undefined;
|
||||||
|
|
||||||
// The current frequency of counter 2
|
/// The current frequency of counter 2
|
||||||
var current_freq_2: u32 = undefined;
|
var current_freq_2: u32 = undefined;
|
||||||
|
|
||||||
var time_ms: u32 = undefined;
|
/// The number of nanoseconds between interrupts.
|
||||||
var time_under_1_ms: u32 = undefined;
|
var time_ns: u32 = undefined;
|
||||||
|
|
||||||
|
/// The number of nanoseconds to be added the to time_ns for time between interrupts.
|
||||||
|
var time_under_1_ns: u32 = undefined;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Send a command to the PIT command register.
|
/// Send a command to the PIT command register.
|
||||||
|
@ -140,96 +202,110 @@ inline fn sendCommand(cmd: u8) void {
|
||||||
arch.outb(COMMAND_REGISTER, cmd);
|
arch.outb(COMMAND_REGISTER, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Read the current mode of the selected counter.
|
||||||
|
///
|
||||||
|
/// Arguments:
|
||||||
|
/// IN counter: CounterSelect - The counter to read the mode the counter is operating in.
|
||||||
|
///
|
||||||
|
/// Return: u8
|
||||||
|
/// The mode the counter is operating in. Use the masks above to get each part.
|
||||||
|
///
|
||||||
|
inline fn readBackCommand(counter: CounterSelect) u8 {
|
||||||
|
sendCommand(0xC2);
|
||||||
|
return u8(0x3F) & arch.inb(counter.getRegister());
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Send data to a given counter. Will be only one of the 3 counters as is an internal function.
|
/// Send data to a given counter. Will be only one of the 3 counters as is an internal function.
|
||||||
///
|
///
|
||||||
/// Arguments:
|
/// Arguments:
|
||||||
/// IN comptime counter: u16 - The counter port to send the data to.
|
/// IN counter: CounterSelect - The counter port to send the data to.
|
||||||
/// IN data: u8 - The data to send.
|
/// IN data: u8 - The data to send.
|
||||||
///
|
///
|
||||||
inline fn sendDateToCounter(comptime counter: u16, data: u8) void {
|
inline fn sendDataToCounter(counter: CounterSelect, data: u8) void {
|
||||||
assert(counter == COUNTER_0_REGISTER or counter == COUNTER_1_REGISTER or counter == COUNTER_2_REGISTER);
|
arch.outb(counter.getRegister(), data);
|
||||||
arch.outb(counter, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pitHandler(context: *arch.InterruptContext) void {
|
///
|
||||||
ticks += 1;
|
/// The interrupt handler for the PIT. This will increment a counter for now.
|
||||||
|
///
|
||||||
|
/// Arguments:
|
||||||
|
/// IN ctx: *arch.InterruptContext - Pointer to the interrupt context containing the contents
|
||||||
|
/// of the register at the time of the interrupt.
|
||||||
|
///
|
||||||
|
fn pitHandler(ctx: *arch.InterruptContext) void {
|
||||||
|
ticks +%= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set up a counter with a tick rate and mode of operation.
|
/// Set up a counter with a tick rate and mode of operation.
|
||||||
///
|
///
|
||||||
/// Arguments:
|
/// Arguments:
|
||||||
/// IN freq: u16 - The frequency that the counter operates at.
|
/// IN counter: CounterSelect - Which counter is to be set up.
|
||||||
/// IN counter: u8 - Which counter is to be set up, either OCW_SELECT_COUNTER_0,
|
/// IN freq: u32 - The frequency that the counter operates at. Any frequency that
|
||||||
/// OCW_SELECT_COUNTER_1 or OCW_SELECT_COUNTER_2 only.
|
/// is between 0..18 (inclusive) or above MAX_FREQUENCY will return
|
||||||
/// IN mode: u8 - The mode of operation that the counter will operate in. See The modes
|
/// an error.
|
||||||
/// definition above to chose which mode the counter is to run at.
|
/// IN mode: u8 - The mode of operation that the counter will operate in. See
|
||||||
|
/// the modes definition above to chose which mode the counter is
|
||||||
|
/// to run at.
|
||||||
///
|
///
|
||||||
fn setupCounter(comptime counter: u8, freq: u32, mode: u8) void {
|
/// Error: PitError:
|
||||||
var reload_value: u32 = 0x10000; // 65536, the slowest possible frequency
|
/// PitError.InvalidFrequency - If the given frequency is out of bounds. Less than 19 or
|
||||||
|
/// greater than MAX_FREQUENCY.
|
||||||
|
///
|
||||||
|
fn setupCounter(counter: CounterSelect, freq: u32, mode: u8) PitError!void {
|
||||||
|
if (freq < 19 or freq > MAX_FREQUENCY) {
|
||||||
|
return PitError.InvalidFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 65536, the slowest possible frequency. Roughly 19Hz
|
||||||
|
var reload_value = u32(0x10000);
|
||||||
|
|
||||||
|
// The lowest possible frequency is 18Hz.
|
||||||
|
// MAX_FREQUENCY / 18 > u16 N
|
||||||
|
// MAX_FREQUENCY / 19 < u16 Y
|
||||||
if (freq > 18) {
|
if (freq > 18) {
|
||||||
|
if (freq < MAX_FREQUENCY) {
|
||||||
|
// Rounded integer division
|
||||||
|
reload_value = (MAX_FREQUENCY + (freq / 2)) / freq;
|
||||||
|
} else {
|
||||||
// The fastest possible frequency if frequency is too high
|
// The fastest possible frequency if frequency is too high
|
||||||
reload_value = 1;
|
reload_value = 1;
|
||||||
|
|
||||||
if (freq < MAX_FREQUENCY) {
|
|
||||||
reload_value = MAX_FREQUENCY / freq;
|
|
||||||
var rem: u32 = MAX_FREQUENCY % freq;
|
|
||||||
|
|
||||||
// Is the remainder more than half
|
|
||||||
if (rem > MAX_FREQUENCY / 2) {
|
|
||||||
// Round up
|
|
||||||
reload_value += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the frequency with the actual one that the PIT will be using
|
||||||
|
// Rounded integer division
|
||||||
|
const frequency = (MAX_FREQUENCY + (reload_value / 2)) / reload_value;
|
||||||
|
|
||||||
|
// Calculate the amount of nanoseconds between interrupts
|
||||||
|
time_ns = u32(1000000000) / frequency;
|
||||||
|
|
||||||
|
// Calculate the number of picoseconds, the left over from nanoseconds
|
||||||
|
time_under_1_ns = ((u32(1000000000) % frequency) * u32(1000) + (frequency / 2)) / frequency;
|
||||||
|
|
||||||
|
// Set the frequency for the counter being set up
|
||||||
|
switch (counter) {
|
||||||
|
.Counter0 => current_freq_0 = frequency,
|
||||||
|
.Counter1 => current_freq_1 = frequency,
|
||||||
|
.Counter2 => current_freq_2 = frequency,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the u16 version as this is what will be loaded into the PIT
|
// Get the u16 version as this is what will be loaded into the PIT
|
||||||
var reload_val_16: u16 = @truncate(u16, reload_value);
|
// If truncating 0x10000, this will equal 0, which is the slowest.
|
||||||
|
const reload_val_16 = @truncate(u16, reload_value);
|
||||||
|
|
||||||
// Update the frequency with the actual one that the PIT will be using
|
// Send the set up command to the PIT
|
||||||
var frequency: u32 = MAX_FREQUENCY / reload_value;
|
sendCommand(mode | OCW_READ_LOAD_DATA | counter.getCounterOCW());
|
||||||
var rem: u32 = MAX_FREQUENCY % reload_value;
|
sendDataToCounter(counter, @truncate(u8, reload_val_16));
|
||||||
|
sendDataToCounter(counter, @truncate(u8, reload_val_16 >> 8));
|
||||||
// Is the remainder more than half
|
|
||||||
if (rem > MAX_FREQUENCY / 2) {
|
|
||||||
// Round up
|
|
||||||
frequency += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the amount of time between IRQs
|
|
||||||
time_ms = reload_value * u32(1000);
|
|
||||||
time_under_1_ms = time_ms % MAX_FREQUENCY;
|
|
||||||
time_ms /= MAX_FREQUENCY;
|
|
||||||
|
|
||||||
comptime const port: u16 = switch (counter) {
|
|
||||||
OCW_SELECT_COUNTER_0 => COUNTER_0_REGISTER,
|
|
||||||
OCW_SELECT_COUNTER_1 => COUNTER_1_REGISTER,
|
|
||||||
OCW_SELECT_COUNTER_2 => COUNTER_2_REGISTER,
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (counter) {
|
|
||||||
OCW_SELECT_COUNTER_0 => current_freq_0 = frequency,
|
|
||||||
OCW_SELECT_COUNTER_1 => current_freq_1 = frequency,
|
|
||||||
OCW_SELECT_COUNTER_2 => current_freq_2 = frequency,
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
|
|
||||||
var command: u8 = mode | OCW_READ_LOAD_DATA | counter;
|
|
||||||
|
|
||||||
sendCommand(command);
|
|
||||||
|
|
||||||
sendDateToCounter(port, @truncate(u8, reload_val_16));
|
|
||||||
sendDateToCounter(port, @truncate(u8, reload_val_16 >> 8));
|
|
||||||
|
|
||||||
// Reset the counter ticks
|
// Reset the counter ticks
|
||||||
switch (counter) {
|
switch (counter) {
|
||||||
OCW_SELECT_COUNTER_0 => ticks = 0,
|
.Counter0 => ticks = 0,
|
||||||
OCW_SELECT_COUNTER_1 => ram_ticks = 0,
|
.Counter1 => ram_ticks = 0,
|
||||||
OCW_SELECT_COUNTER_2 => speaker_ticks = 0,
|
.Counter2 => speaker_ticks = 0,
|
||||||
else => unreachable,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,9 +313,29 @@ fn setupCounter(comptime counter: u8, freq: u32, mode: u8) void {
|
||||||
/// A simple wait that used the PIT to wait a number of ticks.
|
/// A simple wait that used the PIT to wait a number of ticks.
|
||||||
///
|
///
|
||||||
/// Arguments:
|
/// Arguments:
|
||||||
/// IN milliseconds: u32 - The number of ticks to wait.
|
/// IN ticks_to_wait: u32 - The number of ticks to wait.
|
||||||
///
|
///
|
||||||
pub fn waitTicks(ticks_to_wait: u32) void {
|
pub fn waitTicks(ticks_to_wait: u32) void {
|
||||||
|
if (ticks > u32(maxInt(u32)) - ticks_to_wait) {
|
||||||
|
// Integer overflow
|
||||||
|
|
||||||
|
// Calculate the 2 conditions
|
||||||
|
const wait_ticks1 = u32(maxInt(u32)) - ticks;
|
||||||
|
const wait_ticks2 = ticks_to_wait - wait_ticks1;
|
||||||
|
|
||||||
|
while (ticks > wait_ticks1) {
|
||||||
|
arch.enableInterrupts();
|
||||||
|
arch.halt();
|
||||||
|
arch.disableInterrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ticks < wait_ticks2) {
|
||||||
|
arch.enableInterrupts();
|
||||||
|
arch.halt();
|
||||||
|
arch.disableInterrupts();
|
||||||
|
}
|
||||||
|
arch.enableInterrupts();
|
||||||
|
} else {
|
||||||
const wait_ticks = ticks + ticks_to_wait;
|
const wait_ticks = ticks + ticks_to_wait;
|
||||||
while (ticks < wait_ticks) {
|
while (ticks < wait_ticks) {
|
||||||
arch.enableInterrupts();
|
arch.enableInterrupts();
|
||||||
|
@ -247,12 +343,13 @@ pub fn waitTicks(ticks_to_wait: u32) void {
|
||||||
arch.disableInterrupts();
|
arch.disableInterrupts();
|
||||||
}
|
}
|
||||||
arch.enableInterrupts();
|
arch.enableInterrupts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Get the number of ticks that have passed when the PIT was initiated.
|
/// Get the number of ticks that have passed when the PIT was initiated.
|
||||||
///
|
///
|
||||||
/// Return:
|
/// Return: u32
|
||||||
/// Number of ticks passed.
|
/// Number of ticks passed.
|
||||||
///
|
///
|
||||||
pub fn getTicks() u32 {
|
pub fn getTicks() u32 {
|
||||||
|
@ -262,7 +359,7 @@ pub fn getTicks() u32 {
|
||||||
///
|
///
|
||||||
/// Get the frequency the PIT is ticking at.
|
/// Get the frequency the PIT is ticking at.
|
||||||
///
|
///
|
||||||
/// Return:
|
/// Return: u32
|
||||||
/// The frequency the PIT is running at
|
/// The frequency the PIT is running at
|
||||||
///
|
///
|
||||||
pub fn getFrequency() u32 {
|
pub fn getFrequency() u32 {
|
||||||
|
@ -274,12 +371,13 @@ pub fn getFrequency() u32 {
|
||||||
///
|
///
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
log.logInfo("Init pit\n");
|
log.logInfo("Init pit\n");
|
||||||
// Set up counter 0 at 1000hz in a square wave mode counting in binary
|
// Set up counter 0 at 10000hz in a square wave mode counting in binary
|
||||||
// TODO: https://github.com/ziglang/zig/issues/557, Need type defined
|
const freq = u32(10000);
|
||||||
const freq: u32 = 10000;
|
setupCounter(CounterSelect.Counter0, freq, OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY) catch |e| {
|
||||||
setupCounter(OCW_SELECT_COUNTER_0, freq, OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY);
|
panic(@errorReturnTrace(), "Invalid frequency: {}\n", freq);
|
||||||
|
};
|
||||||
|
|
||||||
log.logInfo("Set frequency at: {}Hz, real frequency: {}Hz\n", freq, getFrequency());
|
log.logDebug("Set frequency at: {}Hz, real frequency: {}Hz\n", freq, getFrequency());
|
||||||
|
|
||||||
// Installs 'pitHandler' to IRQ0 (pic.IRQ_PIT)
|
// Installs 'pitHandler' to IRQ0 (pic.IRQ_PIT)
|
||||||
irq.registerIrq(pic.IRQ_PIT, pitHandler) catch |err| switch (err) {
|
irq.registerIrq(pic.IRQ_PIT, pitHandler) catch |err| switch (err) {
|
||||||
|
@ -292,4 +390,252 @@ pub fn init() void {
|
||||||
};
|
};
|
||||||
|
|
||||||
log.logInfo("Done\n");
|
log.logInfo("Done\n");
|
||||||
|
|
||||||
|
if (build_options.rt_test) runtimeTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
test "sendCommand" {
|
||||||
|
arch.initTest();
|
||||||
|
defer arch.freeTest();
|
||||||
|
|
||||||
|
const cmd = u8(10);
|
||||||
|
|
||||||
|
arch.addTestParams("outb", COMMAND_REGISTER, cmd);
|
||||||
|
|
||||||
|
sendCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "readBackCommand" {
|
||||||
|
arch.initTest();
|
||||||
|
defer arch.freeTest();
|
||||||
|
|
||||||
|
const cmd = u8(0xC2);
|
||||||
|
|
||||||
|
arch.addTestParams("outb", COMMAND_REGISTER, cmd);
|
||||||
|
arch.addTestParams("inb", COUNTER_0_REGISTER, u8(0x20));
|
||||||
|
|
||||||
|
const actual = readBackCommand(CounterSelect.Counter0);
|
||||||
|
|
||||||
|
expectEqual(u8(0x20), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "sendDataToCounter" {
|
||||||
|
arch.initTest();
|
||||||
|
defer arch.freeTest();
|
||||||
|
|
||||||
|
const data = u8(10);
|
||||||
|
|
||||||
|
arch.addTestParams("outb", COUNTER_0_REGISTER, data);
|
||||||
|
|
||||||
|
sendDataToCounter(CounterSelect.Counter0, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "setupCounter lowest frequency" {
|
||||||
|
arch.initTest();
|
||||||
|
defer arch.freeTest();
|
||||||
|
|
||||||
|
const counter = CounterSelect.Counter0;
|
||||||
|
const port = counter.getRegister();
|
||||||
|
|
||||||
|
var freq = u32(0);
|
||||||
|
|
||||||
|
// Reload value will be 0 (0x10000), the slowest speed for frequency less than 19
|
||||||
|
const expected_reload_value = u16(0);
|
||||||
|
|
||||||
|
// Slowest frequency the PIT can run at
|
||||||
|
const expected_freq = u32(19);
|
||||||
|
|
||||||
|
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
|
||||||
|
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
|
||||||
|
|
||||||
|
while (freq <= 18) : (freq += 1) {
|
||||||
|
// arch.addTestParams("outb", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8));
|
||||||
|
expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
|
||||||
|
|
||||||
|
// expectEqual(u32(0), ticks);
|
||||||
|
// expectEqual(expected_freq, current_freq_0);
|
||||||
|
// expectEqual(expected_freq, getFrequency());
|
||||||
|
|
||||||
|
// // These are the hard coded expected values. Calculated externally to check the internal calculation
|
||||||
|
// expectEqual(u32(52631578), time_ns);
|
||||||
|
// expectEqual(u32(947), time_under_1_ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset globals
|
||||||
|
time_ns = 0;
|
||||||
|
current_freq_0 = 0;
|
||||||
|
ticks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "setupCounter highest frequency" {
|
||||||
|
arch.initTest();
|
||||||
|
defer arch.freeTest();
|
||||||
|
|
||||||
|
const counter = CounterSelect.Counter0;
|
||||||
|
const port = counter.getRegister();
|
||||||
|
|
||||||
|
// Set the frequency above the maximum
|
||||||
|
const freq = MAX_FREQUENCY + 10;
|
||||||
|
|
||||||
|
// Reload value will be 1, the fastest speed for frequency greater than MAX_FREQUENCY
|
||||||
|
const expected_reload_value = 1;
|
||||||
|
|
||||||
|
// Slowest frequency the PIT can run at
|
||||||
|
const expected_freq = MAX_FREQUENCY;
|
||||||
|
|
||||||
|
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
|
||||||
|
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
|
||||||
|
|
||||||
|
// arch.addTestParams("outb", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8));
|
||||||
|
|
||||||
|
expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
|
||||||
|
|
||||||
|
// expectEqual(u32(0), ticks);
|
||||||
|
// expectEqual(expected_freq, current_freq_0);
|
||||||
|
// expectEqual(expected_freq, getFrequency());
|
||||||
|
|
||||||
|
// // These are the hard coded expected values. Calculated externally to check the internal calculation
|
||||||
|
// expectEqual(u32(838), time_ns);
|
||||||
|
// expectEqual(u32(95), time_under_1_ns);
|
||||||
|
|
||||||
|
// Reset globals
|
||||||
|
time_ns = 0;
|
||||||
|
current_freq_0 = 0;
|
||||||
|
ticks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "setupCounter normal frequency" {
|
||||||
|
arch.initTest();
|
||||||
|
defer arch.freeTest();
|
||||||
|
|
||||||
|
const counter = CounterSelect.Counter0;
|
||||||
|
const port = counter.getRegister();
|
||||||
|
|
||||||
|
// Set the frequency to a normal frequency
|
||||||
|
const freq = 10000;
|
||||||
|
const expected_reload_value = 119;
|
||||||
|
const expected_freq = u32(10027);
|
||||||
|
|
||||||
|
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
|
||||||
|
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
|
||||||
|
|
||||||
|
arch.addTestParams("outb", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8));
|
||||||
|
|
||||||
|
setupCounter(counter, freq, mode) catch unreachable;
|
||||||
|
|
||||||
|
expectEqual(u32(0), ticks);
|
||||||
|
expectEqual(expected_freq, current_freq_0);
|
||||||
|
expectEqual(expected_freq, getFrequency());
|
||||||
|
|
||||||
|
// These are the hard coded expected values. Calculated externally to check the internal calculation
|
||||||
|
expectEqual(u32(99730), time_ns);
|
||||||
|
expectEqual(u32(727), time_under_1_ns);
|
||||||
|
|
||||||
|
// Reset globals
|
||||||
|
time_ns = 0;
|
||||||
|
current_freq_0 = 0;
|
||||||
|
ticks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Test that waiting a number of ticks and then getting the number of ticks match.
|
||||||
|
///
|
||||||
|
fn rt_waitTicks() void {
|
||||||
|
const waiting = 1000;
|
||||||
|
const epsilon = 2 * getFrequency() / 10000;
|
||||||
|
|
||||||
|
const previous_count = getTicks();
|
||||||
|
|
||||||
|
waitTicks(waiting);
|
||||||
|
|
||||||
|
const difference = getTicks() - waiting;
|
||||||
|
|
||||||
|
if (previous_count + epsilon < difference or previous_count > difference + epsilon) {
|
||||||
|
panic(@errorReturnTrace(), "Waiting failed. difference: {}, previous_count: {}. Epsilon: {}\n", difference, previous_count, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.logInfo("PIT: Tested wait ticks\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Test that waiting a number of ticks and then getting the number of ticks match. This version
|
||||||
|
/// checks for the ticks wrap around.
|
||||||
|
///
|
||||||
|
fn rt_waitTicks2() void {
|
||||||
|
// Set the ticks to 16 less than the max
|
||||||
|
const waiting = 1000;
|
||||||
|
const epsilon = 2 * getFrequency() / 10000;
|
||||||
|
|
||||||
|
ticks = 0xFFFFFFF0;
|
||||||
|
const previous_count = getTicks() - 0xFFFFFFF0;
|
||||||
|
|
||||||
|
waitTicks(waiting);
|
||||||
|
|
||||||
|
// maxInt(u32) - u32(0xFFFFFFF0) = 15
|
||||||
|
const difference = getTicks() + 15 - waiting;
|
||||||
|
|
||||||
|
if (previous_count + epsilon < difference or previous_count > difference + epsilon) {
|
||||||
|
panic(@errorReturnTrace(), "Waiting failed. difference: {}, previous_count: {}. Epsilon: {}\n", difference, previous_count, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.logInfo("PIT: Tested wait ticks 2\n");
|
||||||
|
|
||||||
|
// Reset ticks
|
||||||
|
ticks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Check that when the PIT is initialised, counter 0 is set up properly.
|
||||||
|
///
|
||||||
|
fn rt_initCounter_0() void {
|
||||||
|
const expected_ns = u32(99730);
|
||||||
|
const expected_ps = u32(727);
|
||||||
|
const expected_hz = u32(10027);
|
||||||
|
|
||||||
|
if (time_ns != expected_ns or time_under_1_ns != expected_ps or getFrequency() != expected_hz) {
|
||||||
|
panic(
|
||||||
|
@errorReturnTrace(),
|
||||||
|
"Frequency not set properly. Hz: {}!={}, ns: {}!={}, ps: {}!= {}\n",
|
||||||
|
getFrequency(),
|
||||||
|
expected_hz,
|
||||||
|
time_ns,
|
||||||
|
expected_ns,
|
||||||
|
time_under_1_ns,
|
||||||
|
expected_ps,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var irq_exists = false;
|
||||||
|
|
||||||
|
irq.registerIrq(pic.IRQ_PIT, pitHandler) catch |err| switch (err) {
|
||||||
|
error.IrqExists => {
|
||||||
|
// We should get this error
|
||||||
|
irq_exists = true;
|
||||||
|
},
|
||||||
|
error.InvalidIrq => {
|
||||||
|
panic(@errorReturnTrace(), "IRQ for PIT, IRQ number: {} is invalid", pic.IRQ_PIT);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!irq_exists) {
|
||||||
|
panic(@errorReturnTrace(), "IRQ for PIT doesn't exists\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
const expected_mode = OCW_READ_LOAD_DATA | OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_SELECT_COUNTER_0 | OCW_BINARY_COUNT_BINARY;
|
||||||
|
const actual_mode = readBackCommand(CounterSelect.Counter0);
|
||||||
|
|
||||||
|
if (expected_mode != actual_mode) {
|
||||||
|
panic(@errorReturnTrace(), "Operating mode don't not set properly. Found: {}, expecting: {}\n", actual_mode, expected_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.logInfo("PIT: Tested init\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Run all the runtime tests.
|
||||||
|
///
|
||||||
|
fn runtimeTests() void {
|
||||||
|
rt_initCounter_0();
|
||||||
|
rt_waitTicks();
|
||||||
|
rt_waitTicks2();
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,7 +250,7 @@ fn putEntryAt(char: u8, x: u8, y: u8) TtyError!void {
|
||||||
/// TtyError.OutOfBounds - If trying to move up more rows on a page.
|
/// TtyError.OutOfBounds - If trying to move up more rows on a page.
|
||||||
///
|
///
|
||||||
fn pagesMoveRowsUp(rows: u16) TtyError!void {
|
fn pagesMoveRowsUp(rows: u16) TtyError!void {
|
||||||
// Out of bounds check, also no need to move 0 rows
|
// Out of bounds check
|
||||||
if (rows > ROW_TOTAL) {
|
if (rows > ROW_TOTAL) {
|
||||||
return TtyError.OutOfBounds;
|
return TtyError.OutOfBounds;
|
||||||
}
|
}
|
||||||
|
@ -284,13 +284,16 @@ fn pagesMoveRowsUp(rows: u16) TtyError!void {
|
||||||
/// TtyError.OutOfBounds - If trying to move up more rows on a page. This shouldn't happen
|
/// TtyError.OutOfBounds - If trying to move up more rows on a page. This shouldn't happen
|
||||||
/// as bounds checks have been done.
|
/// as bounds checks have been done.
|
||||||
///
|
///
|
||||||
fn scroll() TtyError!void {
|
fn scroll() void {
|
||||||
// Added the condition in the if from pagesMoveRowsUp as don't need to move all rows
|
// Added the condition in the if from pagesMoveRowsUp as don't need to move all rows
|
||||||
if (row >= vga.HEIGHT and (row - vga.HEIGHT + 1) <= ROW_TOTAL) {
|
if (row >= vga.HEIGHT and (row - vga.HEIGHT + 1) <= ROW_TOTAL) {
|
||||||
const rows_to_move = row - vga.HEIGHT + 1;
|
const rows_to_move = row - vga.HEIGHT + 1;
|
||||||
|
|
||||||
// Move rows up pages by temp, will usually be one.
|
// Move rows up pages by temp, will usually be one.
|
||||||
try pagesMoveRowsUp(rows_to_move);
|
// TODO: Maybe panic here as we have the check above, so if this fails, then is a big problem
|
||||||
|
pagesMoveRowsUp(rows_to_move) catch |e| {
|
||||||
|
panic(@errorReturnTrace(), "Can't move {} rows up. Must be less than {}\n", rows_to_move, ROW_TOTAL);
|
||||||
|
};
|
||||||
|
|
||||||
// Move all rows up by rows_to_move
|
// Move all rows up by rows_to_move
|
||||||
var i = u32(0);
|
var i = u32(0);
|
||||||
|
@ -333,14 +336,14 @@ fn putChar(char: u8) TtyError!void {
|
||||||
'\n' => {
|
'\n' => {
|
||||||
column = 0;
|
column = 0;
|
||||||
row += 1;
|
row += 1;
|
||||||
try scroll();
|
scroll();
|
||||||
},
|
},
|
||||||
'\t' => {
|
'\t' => {
|
||||||
column += 4;
|
column += 4;
|
||||||
if (column >= vga.WIDTH) {
|
if (column >= vga.WIDTH) {
|
||||||
column -= @truncate(u8, vga.WIDTH);
|
column -= @truncate(u8, vga.WIDTH);
|
||||||
row += 1;
|
row += 1;
|
||||||
try scroll();
|
scroll();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'\r' => {
|
'\r' => {
|
||||||
|
@ -363,7 +366,7 @@ fn putChar(char: u8) TtyError!void {
|
||||||
if (column == vga.WIDTH) {
|
if (column == vga.WIDTH) {
|
||||||
column = 0;
|
column = 0;
|
||||||
row += 1;
|
row += 1;
|
||||||
try scroll();
|
scroll();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1203,7 +1206,7 @@ test "scroll row is less then max height" {
|
||||||
incrementingPagesTesting();
|
incrementingPagesTesting();
|
||||||
|
|
||||||
// Call function
|
// Call function
|
||||||
try scroll();
|
scroll();
|
||||||
|
|
||||||
// Post test
|
// Post test
|
||||||
defaultVariablesTesting(0, 0, 0);
|
defaultVariablesTesting(0, 0, 0);
|
||||||
|
@ -1229,7 +1232,7 @@ test "scroll row is equal to height" {
|
||||||
|
|
||||||
// Call function
|
// Call function
|
||||||
// Rows move up one
|
// Rows move up one
|
||||||
try scroll();
|
scroll();
|
||||||
|
|
||||||
// Post test
|
// Post test
|
||||||
defaultVariablesTesting(0, vga.HEIGHT - 1, 0);
|
defaultVariablesTesting(0, vga.HEIGHT - 1, 0);
|
||||||
|
@ -1280,7 +1283,7 @@ test "scroll row is more than height" {
|
||||||
|
|
||||||
// Call function
|
// Call function
|
||||||
// Rows move up 5
|
// Rows move up 5
|
||||||
try scroll();
|
scroll();
|
||||||
|
|
||||||
// Post test
|
// Post test
|
||||||
defaultVariablesTesting(0, vga.HEIGHT - 1, 0);
|
defaultVariablesTesting(0, vga.HEIGHT - 1, 0);
|
||||||
|
|
|
@ -10,7 +10,10 @@ def get_test_cases(TestCase):
|
||||||
TestCase("ISR tests", [r"ISR: Tested registered handlers", r"ISR: Tested opened IDT entries"]),
|
TestCase("ISR tests", [r"ISR: Tested registered handlers", r"ISR: Tested opened IDT entries"]),
|
||||||
TestCase("IRQ init", [r"Init irq", r"Done"]),
|
TestCase("IRQ init", [r"Init irq", r"Done"]),
|
||||||
TestCase("IRQ tests", [r"IRQ: Tested registered handlers", r"IRQ: Tested opened IDT entries"]),
|
TestCase("IRQ tests", [r"IRQ: Tested registered handlers", r"IRQ: Tested opened IDT entries"]),
|
||||||
TestCase("PIT init", [r"Init pit", r".+", r"Done"]),
|
TestCase("PIT init", [r"Init pit"]),
|
||||||
|
TestCase("PIT init", [r".+"], r"\[DEBUG\] "),
|
||||||
|
TestCase("PIT init", [r"Done"]),
|
||||||
|
TestCase("PIT tests", [r"PIT: Tested init", r"PIT: Tested wait ticks", r"PIT: Tested wait ticks 2"]),
|
||||||
TestCase("Paging init", [r"Init paging", r"Done"]),
|
TestCase("Paging init", [r"Init paging", r"Done"]),
|
||||||
TestCase("Paging tests", [r"Paging: Tested accessing unmapped memory", r"Paging: Tested accessing mapped memory"]),
|
TestCase("Paging tests", [r"Paging: Tested accessing unmapped memory", r"Paging: Tested accessing mapped memory"]),
|
||||||
TestCase("Syscalls init", [r"Init syscalls", r"Done"]),
|
TestCase("Syscalls init", [r"Init syscalls", r"Done"]),
|
||||||
|
|
|
@ -91,3 +91,9 @@ pub fn init(mem_profile: *const MemProfile, allocator: *Allocator, comptime opti
|
||||||
// When I come on to the mem.zig testing, I'll fix :)
|
// When I come on to the mem.zig testing, I'll fix :)
|
||||||
//return mock_framework.performAction("init", void, mem_profile, allocator);
|
//return mock_framework.performAction("init", void, mem_profile, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// User defined mocked functions
|
||||||
|
|
||||||
|
pub fn mock_disableInterrupts() void {}
|
||||||
|
|
||||||
|
pub fn mock_enableInterrupts() void {}
|
||||||
|
|
Loading…
Reference in a new issue