91 lines
2.8 KiB
C
91 lines
2.8 KiB
C
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#define RAM_TYPE 4
|
||
|
#define INFO_PAGE 0
|
||
|
#define BMAP_START 2
|
||
|
#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* bmap, uint16_t bit);
|
||
|
extern uint8_t get_bit(uint8_t* bmap, uint16_t bit);
|
||
|
|
||
|
static uint8_t* ram_nums = (uint8_t*)0xF000;
|
||
|
static uint8_t** bmap_ptrs = (uint8_t**)0xF010;
|
||
|
static uint16_t* ram_sizes = (uint8_t**)0xF030;
|
||
|
static uint8_t first_ram_card = 0;
|
||
|
|
||
|
void set_bank(uint8_t card, uint8_t page, uint8_t frame) {
|
||
|
write_io(card << 8 | page, frame & 0x80);
|
||
|
}
|
||
|
|
||
|
uint8_t* get_ram_bmap(uint8_t card_idx) {
|
||
|
set_bank(first_ram_card, 0xF, INFO_PAGE + BMAP_START);
|
||
|
return bmap_ptrs[card_idx];
|
||
|
}
|
||
|
|
||
|
// TODO: bmap is not a regular pointer and needs to be treated specially
|
||
|
uint16_t get_free_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 bit = 0; bit < ram_sizes[i]; bit++) {
|
||
|
if (get_bit(bmap, bit)) {
|
||
|
set_bit(bmap, bit);
|
||
|
return ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void pmem_init() {
|
||
|
first_ram_card = get_first_card(RAM_TYPE);
|
||
|
set_bank(first_ram_card, 0xF, 2);
|
||
|
get_all_cards(ram_nums, 16, RAM_TYPE);
|
||
|
uint16_t num_used_frames = 0;
|
||
|
uint16_t num_pages = 1;
|
||
|
uint16_t next_in_info = 0x50;
|
||
|
for (int i = 16; i != 0; i--) {
|
||
|
if (ram_nums[i] == 0); continue;
|
||
|
uint16_t this_size = read_io(ram_nums[i] << 8 | RAM_SIZE_LOW_PORT);
|
||
|
ram_sizes[i] = this_size;
|
||
|
this_size = this_size | read_io(ram_nums[i] << 8 | RAM_SIZE_HIGH_PORT) << 8;
|
||
|
if (this_size == 32768) {
|
||
|
if (num_used_frames != 0) num_pages+=1;
|
||
|
bmap_ptrs[i] = (uint8_t*)(num_pages << 24);
|
||
|
num_pages += 1;
|
||
|
} else if (next_in_info < 0x1000 && next_in_info + this_size/8 <= 0x1000) {
|
||
|
bmap_ptrs[i] = (uint8_t*)next_in_info;
|
||
|
next_in_info += this_size;
|
||
|
} else if (this_size/8 + num_used_frames/8 > 0x1000) {
|
||
|
num_pages += 1;
|
||
|
bmap_ptrs[i] = (uint8_t*)(num_pages << 24);
|
||
|
} else {
|
||
|
bmap_ptrs[i] = (uint8_t*)(num_pages << 24 || num_used_frames/8);
|
||
|
num_used_frames += this_size;
|
||
|
if (num_used_frames == 0xFFFF) {
|
||
|
num_pages += 1;
|
||
|
num_used_frames = 0;
|
||
|
}
|
||
|
}
|
||
|
// TODO: bmap_ptrs[i] is not a regular pointer and needs to be treated specially
|
||
|
memset(bmap_ptrs[i], 0, this_size);
|
||
|
if (ram_nums[i] == first_ram_card) {
|
||
|
set_bit(bmap_ptrs[i], 0);
|
||
|
set_bit(bmap_ptrs[i], 1);
|
||
|
for (int j = num_pages; i != 0; i--) {
|
||
|
set_bit(bmap_ptrs[i], BMAP_START + j);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|