88 lines
2.5 KiB
C
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);
|
||
|
}
|
||
|
}
|