Last active
June 10, 2024 08:10
-
-
Save dan-rodrigues/1e2805267d364e72979cbd3c45c58e8a to your computer and use it in GitHub Desktop.
neo homebrew sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdbool.h> | |
// Reg defines, to extract to some header | |
#define REG_VRAMADDR (*((volatile uint16_t *)0x3c0000)) | |
#define REG_VRAMDATA (*((volatile uint16_t *)0x3c0002)) | |
#define REG_VRAMINC (*((volatile uint16_t *)0x3c0004)) | |
#define REG_LSPCMODE (*((volatile uint16_t *)0x3c0006)) | |
#define REG_INT_TIMER (*((volatile uint32_t *)0x3c0008)) | |
#define REG_INT_TIMER_HI (*((volatile uint16_t *)0x3c0008)) | |
#define REG_INT_TIMER_LO (*((volatile uint16_t *)0x3c000a)) | |
#define REG_INT_TIMER_PAUSE (*((volatile uint16_t *)0x3c000e)) | |
// --- | |
#define REG_WATCHDOG (*((volatile uint8_t *)0x300001)) | |
// --- | |
#define PALETTE ((volatile uint16_t *)0x400000) | |
// --- | |
// Quick and dirty prog headers | |
// These would mostly be handled by the linker script rather than being fully defined here | |
typedef struct M68kVectors { | |
uint32_t reset_sp; | |
uint32_t irq_vectors[63]; | |
} __attribute__((packed)) M68kVectors; | |
void user_entry(void); | |
typedef struct ProgHeader { | |
uint8_t recognition_code_1[7]; | |
uint8_t system_type; | |
uint16_t ngh; | |
uint32_t prog_size; | |
uint32_t wram_backup; | |
uint16_t wram_backup_size; | |
uint8_t eyectacher_config; | |
uint8_t eyectacher_sprite_bank; | |
const uint8_t *jp_softdips; | |
const uint8_t *us_softdips; | |
const uint8_t *eu_softdips; | |
uint16_t user_jmp_op; | |
const void *user_entry; | |
// ... | |
uint8_t padding[0x5a]; | |
// ... | |
const void *recognition_code_2; | |
} __attribute__((packed)) ProgHeader; | |
__attribute__((used)) | |
__attribute__ ((section (".vectors"))) | |
static const M68kVectors vectors = { | |
.reset_sp = 0x010f300, | |
.irq_vectors = { | |
// BERR | |
// ... | |
// VBL etc... | |
// ... | |
} | |
}; | |
static const uint32_t recognition_code_2[] = { | |
0x76004A6D, 0x0A146600, 0x003C206D, 0x0A043E2D, | |
0x0A0813C0, 0x00300001, 0x32100C01, 0x00FF671A, | |
0x30280002, 0xB02D0ACE, 0x66103028, 0x0004B02D, | |
0x0ACF6606, 0xB22D0AD0, 0x67085088, 0x51CFFFD4, | |
0x36074E75, 0x206D0A04, 0x3E2D0A08, 0x3210E049, | |
0x0C0100FF, 0x671A3010, 0xB02D0ACE, 0x66123028, | |
0x0002E048, 0xB02D0ACF, 0x6606B22D, 0x0AD06708, | |
0x588851CF, 0xFFD83607, | |
0x4e750000 | |
}; | |
__attribute__((used)) | |
__attribute__ ((section (".prog_header"))) | |
static const ProgHeader header = { | |
.recognition_code_1 = { 'N', 'E', 'O', '-', 'G', 'E', 'O'}, | |
.system_type = 0, | |
.ngh = 0x4040, | |
.recognition_code_2 = recognition_code_2, | |
.eyectacher_config = 2, | |
.user_jmp_op = 0x4ef9, | |
.user_entry = user_entry | |
}; | |
// --- | |
void vram_clear(uint16_t address, uint16_t length, uint16_t data) { | |
REG_WATCHDOG = 0; | |
REG_VRAMADDR = address; | |
REG_VRAMINC = 1; | |
for (uint16_t i = 0; i < length; i++) { | |
REG_VRAMDATA = data; | |
} | |
REG_WATCHDOG = 0; | |
} | |
void fix_clear() { | |
vram_clear(0x7000, 0x500, ' '); | |
} | |
void pal_clear() { | |
REG_WATCHDOG = 0; | |
for (uint16_t i = 0; i < 0x1000; i++) { | |
PALETTE[i] = 0x8000; | |
} | |
REG_WATCHDOG = 0; | |
} | |
void pal_write(uint8_t palette, uint8_t index, uint16_t data) { | |
PALETTE[palette * 0x10 + index] = data; | |
} | |
uint16_t fix_location_vram(uint8_t x, uint8_t y) { | |
return 0x7000 + x * 0x20 + y; | |
} | |
void fix_write(uint8_t x, uint8_t y, const char *string) { | |
REG_VRAMINC = 0x20; | |
char c = 0; | |
const char *source = string; | |
// Top half of 8x16 glyph | |
REG_VRAMADDR = fix_location_vram(x, y); | |
while (c = (*source++)) { | |
REG_VRAMDATA = c | 0x100; | |
} | |
// Bottom half of 8x16 glyph | |
REG_VRAMADDR = fix_location_vram(x, y + 1); | |
source = string; | |
while (c = (*source++)) { | |
REG_VRAMDATA = c | 0x200; | |
} | |
} | |
__attribute__((noreturn)) | |
void user_entry() { | |
vram_clear(0x0000, 0x8000, 0x0000); | |
fix_clear(); | |
pal_clear(); | |
pal_write(0, 1, 0x7fff); | |
pal_write(0, 2, 0x8000); | |
const char *greeting = "Hello world!"; | |
const uint8_t x = 14; | |
const uint8_t y = 14; | |
fix_write(x, y, greeting); | |
while (true) { | |
REG_WATCHDOG = 0; | |
} | |
__builtin_unreachable(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment