slkern/bitarray.c

217 lines
4.8 KiB
C

/* NEW CODE for optimised bit array.
* Copyright (C) 2024 Zak Fenton
* NO WARRANTY USE AT YOUR OWN RISK etc. under terms of UNLICENSE or MIT license
*/
#include "types.h"
#include "param.h"
#include "memlayout.h"
#include "sched.h"
#include "riscv.h"
#include "proc.h"
#include "bitarray.h"
#include "defs.h"
#include "kprintf.h"
struct bitarray* bitarrayalloc(int nbits) {
int i;
if (nbits > 64*64) {
panic("argument to bitarrayalloc is too large");
}
if (sizeof(struct bitarray) >= PGSIZE) {
panic("bitarray structure too large to fit in a page");
}
struct bitarray* result = kalloc();
result->size = nbits;
if (result == (void*)0ULL) {
panic("failed to allocate bitarray structure");
}
initlock(&(result->lock), "bitarray");
for (i = 0; i < 64; i++) {
result->data[i] = 0ULL;
}
return result;
}
int bitarray_get(struct bitarray* a, int index) {
if (index < 0 || index >= a->size) {
return 0;
}
acquire(&(a->lock));
uint64 x = a->data[index>>6];
if ((x & (1ULL << (index & 63))) != 0) {
//printf("Bit at %p # %d is ON\n", a, index);
release(&(a->lock));
return 1;
}
//printf("Bit at %p # %d is OFF\n", a, index);
release(&(a->lock));
return 0;
}
int bitarray_getnolock(struct bitarray* a, int index) {
if (index < 0 || index >= a->size) {
return 0;
}
uint64 x = a->data[index>>6];
if ((x & (1ULL << (index & 63))) != 0) {
//printf("Bit at %p # %d is ON\n", a, index);
return 1;
}
//printf("Bit at %p # %d is OFF\n", a, index);
return 0;
}
/*#ifdef _ZCC
int __naked bitarraylsb(uint64 x) __asm {
ctz a1, a1
ret
// addi a2, zero, 0
// addi a4, zero, 1
// .lsbloop:
// and a3, a1, a4
// bne a3, zero, .lsbend
// srli a1, a1, 1
// addi a2, a2, 1
// j .lsbloop
// .lsbend:
// addi a1, a2, 0
// ret
}
int __naked bitarraylsb2(uint64 i, uint64 x) __asm {
srl a3, a2, a1
ctz a4, a3
add a1, a1, a4
ret
addi a4, zero, 1
addi a6, zero, 64
.lsb2loop:
srl a3, a2, a1
and a5, a4, a1
bne a5, zero, .lsb2end
addi a1, a1, 1
beq a1, a6, .lsb2nope
j .lsb2loop
.lsb2nope:
addi a1, zero, -1
.lsb2end:
ret
}
#else*/
int bitarraylsb(uint64 x) {
int i;
for (i = 0; i < 64; i++) {
if (x & (1ULL << i)) {
return i;
}
}
return -1;
}
int bitarraylsb2(int starti, uint64 x) {
for (; starti < 64; starti++) {
if (x & (1ULL << starti)) {
return starti;
}
}
return -1;
}
//#endif
int bitarraynextnzw(uint64* w, int start, int lim) {
int i;
for (i = start; i < lim; i++) {
if (w[i]) {
return i;
}
}
return -1;
}
void bitarray_setnolock(struct bitarray* a, int index, int val) {
//printf("Setting %p # %d to %s\n", a, index, val ? "ON" : "OFF");
if (index < 0 || index >= a->size) {
panic("invalid index argument to bitarray_setnolock");
}
uint64 x = a->data[index>>6];
if (val) {
a->data[index>>6] = x | (1ULL << (index & 63));
} else {
a->data[index>>6] = x & ~(1ULL << (index & 63));
}
}
int bitarray_findlowest(struct bitarray* a, int startidx) {
//printf("Finding lowest set bit in %p from # %d\n", a, startidx);
if (startidx < 0 || startidx >= a->size) {
return -1;
//startidx = 0;
}
acquire(&(a->lock));
int i;
//uartputc_sync('a');
i = bitarraylsb2(startidx & 63, a->data[startidx>>6]);
if (i < 0) {
i = ((startidx >> 6) + 1) << 6;
//for (i = startidx; (i & 63) != 0 && i < a->size; i++) {
/*if (bitarray_getnolock(a, i)) {
release(&(a->lock));
return i;
}*/
//}
} else {
//uartputc_sync('A');
release(&(a->lock));
//printf("Got %d (path 1)\n", i + ((startidx >> 6) << 6));
return i + ((startidx >> 6) << 6);
}
//uartputc_sync('b');
for (; i < a->size; i+=64) {
uint64 x = a->data[i>>6];
if (x) {
release(&(a->lock));
//printf("Got %d (path 2)\n", i+bitarraylsb(x));
return i+bitarraylsb(x);
}
}
//uartputc_sync('c');
release(&(a->lock));
return -1;
}
int bitarray_poplowest(struct bitarray* a, int startidx) {
if (startidx < 0 || startidx >= a->size) {
startidx = 0;
}
acquire(&(a->lock));
int i;
for (i = startidx; i < a->size; i++) {
if ((i & 63) == 0) {
uint64 x = a->data[i>>6];
if (x == 0ULL) {
i += 63;
}
}
if (bitarray_getnolock(a, i)) {
bitarray_setnolock(a, i, 0);
release(&(a->lock));
return i;
}
}
release(&(a->lock));
return -1;
}
void bitarray_set(struct bitarray* a, int index, int val) {
//printf("Setting %p # %d to %s\n", a, index, val ? "ON" : "OFF");
if (index < 0 || index >= a->size) {
panic("invalid index argument to bitarray_set");
}
acquire(&(a->lock));
uint64 x = a->data[index>>6];
if (val) {
a->data[index>>6] = x | (1ULL << (index & 63));
} else {
a->data[index>>6] = x & ~(1ULL << (index & 63));
}
release(&(a->lock));
}