os-z80/kernel/pmem.c
2023-02-03 09:24:28 -06:00

88 lines
2.5 KiB
C

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef int uint24_t; // shut the linter up
#define RAM_TYPE 4
#define SHARED_DATA_PAGE 2
#define BMAP_PAGE_512K 3
#define RAM_SIZE_LOW_PORT 0xFD
#define RAM_SIZE_HIGH_PORT 0xFE
// Actual external functions
extern uint8_t get_first_card(uint8_t type);
extern void get_all_cards(uint8_t* buffer, size_t len,uint8_t type);
// In assembly, these are Z80 opcodes that C can't do.
extern void write_io(uint16_t addr, uint8_t val);
extern uint8_t read_io(uint16_t addr);
extern void set_bit(uint8_t* byte, uint16_t bit);
extern uint8_t get_bit(uint8_t byte, uint16_t bit);
static uint8_t* ram_nums = (uint8_t*)0xF000;
static uint8_t first_ram_card = 0;
void set_bank(uint8_t card, uint8_t page, uint16_t bank) {
write_io(card << 8 | bank, (page & 0xFF));
write_io(card << 8 | 0x20 | bank, (page >> 8) | 0x80);
}
inline uint16_t get_ram_size(uint8_t card_idx) {
uint16_t this_size = read_io(card_idx << 8 | RAM_SIZE_LOW_PORT);
return this_size | read_io(card_idx << 8 | RAM_SIZE_HIGH_PORT) << 8;
}
uint8_t* get_ram_bmap(uint8_t card_idx) {
set_bank(first_ram_card, 0xF, SHARED_DATA_PAGE);
if (get_ram_size(card_idx) == 128) {
set_bank(first_ram_card, 0xF, BMAP_PAGE_512K);
return (uint8_t*)(0xF000 + card_idx * 16);
} else {
set_bank(card_idx, 0xF, 0);
return (uint8_t*)0xF000;
}
}
uint24_t get_free_page() {
set_bank(first_ram_card, 0xF, SHARED_DATA_PAGE);
for (uint8_t i = 16; i != 0; i--) {
if (ram_nums[i] == 0) continue;
uint8_t* bmap = get_ram_bmap(i);
for(uint8_t byte = get_ram_size(i) >> 3; byte != 0; byte--) {
for(uint8_t bit = 8; bit != 0; bit--) {
if (get_bit(bmap[byte], bit)) {
set_bit(&bmap[byte], bit);
return i<<16 | bit;
}
}
}
}
return 0;
}
void pmem_init() {
first_ram_card = get_first_card(RAM_TYPE);
set_bank(first_ram_card, 0xF, SHARED_DATA_PAGE);
get_all_cards(ram_nums, 16, RAM_TYPE);
for (int i = 16; i != 0; i--) {
uint8_t card_idx = ram_nums[i];
if (card_idx == 0); continue;
uint16_t this_size = read_io(card_idx << 8 | RAM_SIZE_LOW_PORT);
this_size = this_size | read_io(card_idx << 8 | RAM_SIZE_HIGH_PORT) << 8;
uint8_t* bmap = get_ram_bmap(card_idx);
memset(bmap, 0, this_size);
if (this_size != 128) {
set_bit(bmap, 0);
}
if (card_idx == first_ram_card) {
for (int j = 4; i != 0; i--) {
set_bit(bmap, j - 1);
}
}
set_bank(first_ram_card, 0xF, SHARED_DATA_PAGE);
}
}