This commit is contained in:
y4my4my4m 2023-09-03 17:04:24 +09:00
parent b32f9cea77
commit 5055a3b7f8
14 changed files with 1161 additions and 0 deletions

View file

@ -0,0 +1,21 @@
class NoteCell {
U8 note; // MIDI note number
U8 velocity; // Volume/Intensity
U8 instrument;
U8 effect; // Future expansion for effects
};
#define TRACK_LENGTH 64 // Length of each pattern in rows
class Pattern {
NoteCell cells[TRACK_LENGTH];
};
#define MAX_PATTERNS 64 // Maximum patterns in a song
class Song {
U8 patternOrder[MAX_PATTERNS]; // Which pattern is played when
Pattern patterns[MAX_PATTERNS];
};
#define SAMPLE_RATE 44100
#define PI 3.1415926535897932 // i know i can just use the pi symbol

240
src/Home/Tracker/Lib/AC97.ZC Executable file
View file

@ -0,0 +1,240 @@
#define INT_LAST_VALID_ENTRY 1 << 2
#define INT_IOC 1 << 3
#define INT_FIFO_ERR 1 << 4
#define BDL_BUF_SIZE 2044
#define MAX_BDLS 32
#define PCM_BUF_SIZE 2048
#define PCM_IN 0
#define PCM_OUT 1
#define MIC_IN 2
// Native Audio Mixer registers (all U16)
#define RESET 0x00 // Reset Register
#define MASTER_VOL 0x02 // Set Master Output Volume
#define MIC_VOL 0x0E // Set Microphone Volume
#define PCM_VOL 0x18 // Set Output Volume of PCM patterns
#define REC_SLC 0x1A // Select Input Device
#define REC_GAIN 0x1C // Set Input Gain
#define MIC_GAIN 0x1E // Set Gain of Microphone
#define EXT_ID 0x28 // Supported extended functions
#define EXT_CTRL 0x2A // Enabling extended functions
#define EXT_FRONT_RATE 0x2C // Sample rate of front speaker
// Native Audio Bus Master registers
#define PCM_INPUT_REG_BOX 0x00 // NABM register box for PCM IN (sizeof NABM register box)
#define PCM_OUTPUT_REG_BOX 0x10 // NABM register box for PCM OUT (sizeof NABM register box)
#define MIC_INPUT_REG_BOX 0x20 // NABM register box for Microphone (sizeof NABM register box)
#define GLOBAL_CTL 0x2C // Global Control Register (U32)
#define GLOBAL_STS 0x30 // Global Status Register (U32)
// NABM register box registers
#define BUFFER_DSC_ADDR 0x00 // Physical Address of Buffer Descriptor List (U32)
#define CUR_ENTRY_VAL 0x04 // Number of Actual Processed Buffer Descriptor Entry (U8)
#define LAST_VALID_ENTRY 0x05 // Number of all Descriptor Entries (U8)
#define TRANSFER_STS 0x06 // Status of Transferring Data (U16)
#define CUR_IDX_PROC_SAMPLES 0x08 // Number of Transferred Samples in Actual Processed Entry (U16)
#define PRCSD_ENTRY 0x0A // Number of Actual Processed Buffer Entry (U8)
#define BUFFER_CNT 0x0B // Most Important Register for controlling Transfers (U8)
class CAC97BufferDescriptorListEntry
{
U32 addr;
U16 length; // length - 1
U16 flags;
};
class CAC97BufferDescriptorList
{
CAC97BufferDescriptorListEntry entries[32];
};
class CAC97
{
CPCIInfo pci;
CAC97BufferDescriptorList *bdl[3];
U16 nam;
U16 nabm;
};
CAC97 ac97;
#define AUDIO_MAX_STREAMS 16
#define AUDIO_OUTPUT_BUFFER_SIZE 1024
#define AUDIO_STREAM_FIFO_SIZE 1048576 * 16
#define AUDIO_STREAM_TYPE_INPUT 0
#define AUDIO_STREAM_TYPE_OUTPUT 1
class CAudioStream
{
CFifoI64 *data;
};
class CAudio
{
CAudioStream output[AUDIO_MAX_STREAMS];
I64 output_frames[AUDIO_MAX_STREAMS];
};
CAudio audio;
U0 AudioInit()
{
I64 i = 0;
for (i = 0; i < AUDIO_MAX_STREAMS; i++)
audio.output[i].data = FifoI64New(AUDIO_STREAM_FIFO_SIZE, sys_task);
}
AudioInit;
I64 AudioAvailableOutputStreamGet()
{
I64 stream = 0;
while (FifoI64Count(audio.output[stream].data))
stream++;
if (stream > AUDIO_MAX_STREAMS - 1)
return -1;
return stream;
}
I64 AudioSFXPlay(U32 *data, I64 length)
{
I64 i;
I64 stream = AudioAvailableOutputStreamGet;
if (stream < 0)
return stream;
for (i = 0; i < length; i++)
FifoI64Ins(audio.output[stream].data, data[i]);
return stream;
}
U0 AC97OutputMix(U32 *buf, I64 length = NULL)
{
I64 i;
I64 j;
I64 acc_sample_L = 0;
I64 acc_sample_R = 0;
I64 acc_streams = 0;
U32 sample;
if (!length)
length = AUDIO_OUTPUT_BUFFER_SIZE;
for (i = 0; i < length / 4; i++)
{
acc_sample_L = 0;
acc_sample_R = 0;
acc_streams = 0;
for (j = 0; j < AUDIO_MAX_STREAMS; j++)
{
if (FifoI64Count(audio.output[j].data))
{
FifoI64Remove(audio.output[j].data, &sample);
audio.output_frames[j]++;
acc_streams++;
acc_sample_L += sample.u16[0];
acc_sample_R += sample.u16[1];
}
}
buf[i].i16[0] = ToI64(acc_sample_L / Sqrt(acc_streams));
buf[i].i16[1] = ToI64(acc_sample_R / Sqrt(acc_streams));
}
}
U0 AC97BufferFill()
{
I64 idx = InU8(ac97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY);
U32 *buf = ac97.bdl[PCM_OUT]->entries[idx].addr;
AC97OutputMix(buf, BDL_BUF_SIZE);
OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY, ++idx);
}
U0 AC97AudioProcess()
{
U16 status = InU16(ac97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS);
if (status & INT_IOC)
{
AC97BufferFill;
OutU16(ac97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS, 0x1C);
}
}
I64 AC97Init()
{
I64 i;
I64 j;
// Scan for device
j = PCIClassFind(0x040100, 0);
if (j < 0)
{
device_not_found: SysLog("\n[AC'97] Device not found\n");
return -1;
}
PCIInfoGet(j, &ac97.pci);
if (ac97.pci.vendor_id != 0x8086 || ac97.pci.device_id != 0x2415)
goto device_not_found;
ac97.nam = ac97.pci.bar[0] &0xFFFFFF00;
ac97.nabm = ac97.pci.bar[1] &0xFFFFFF00;
// Enable port IO, disable MMIO
PCIWriteU8(j.u8[2], j.u8[1], j.u8[0], 0x4, 5);
OutU32(ac97.nabm + GLOBAL_CTL, 0x03);
OutU16(ac97.nam + RESET, 0xFFFF);
// Set PCM Output to Max volume
OutU16(ac97.nam + PCM_VOL, 0x0000);
// Allocate Buffer Descriptor Lists
ac97.bdl[PCM_IN] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap);
ac97.bdl[PCM_OUT] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap);
ac97.bdl[MIC_IN] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap);
for (i = 0; i < MAX_BDLS; i++)
{
ac97.bdl[PCM_OUT]->entries[i].addr =
CAllocAligned(PCM_BUF_SIZE, 4096, Fs->code_heap);
ac97.bdl[PCM_OUT]->entries[i].length = BDL_BUF_SIZE / 2;
ac97.bdl[PCM_OUT]->entries[i].flags = 1 << 15;
}
// Set addresses of Buffer Descriptor Lists
// OutU32(ac97.nabm + PCM_INPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[PCM_IN]);
OutU32(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[PCM_OUT]);
// OutU32(ac97.nabm + MIC_INPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[MIC_IN]);
// Set Master Volume
OutU16(ac97.nam + MASTER_VOL, 0x0F0F);
// Stop playing sound
OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 0);
// Fill one buffers
AC97BufferFill;
// Enable interrupt handler
//@pci_register_int_handler(&@ac97_int_handler);
// Start playing sound
OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 1);
return 0;
}
U0 AC97Task()
{
while (1)
{
AC97AudioProcess;
Sleep(1);
}
}
AC97Init;
Spawn(&AC97Task,, "AC97 Task", 1);

21
src/Home/Tracker/Lib/Debug.ZC Executable file
View file

@ -0,0 +1,21 @@
class Debug {
Bool enabled;
I64 bookmark;
I64 counter;
};
Debug debug;
debug.bookmark = 0;
debug.counter = 0;
debug.enabled = FALSE;
U0 debug_print(U8 *fmt, ...) {
if (!debug.enabled || debug.counter < debug.bookmark) {
debug.counter++;
return;
}
U8 *buf = StrPrintJoin(NULL, fmt, argc, argv);
"[%05d] %s", debug.counter, buf;
Free(buf);
debug.counter++;
}

355
src/Home/Tracker/Lib/ELF64.ZC Executable file
View file

@ -0,0 +1,355 @@
#define EI_NIDENT 16
#define EM_X86_64 0x3E
#define ET_EXEC 2
#define ET_DYN 3
#define STT_OBJECT 1
#define STT_FUNC 2
class Elf64_Ehdr {
U8 e_ident[EI_NIDENT]; /* Magic number and other info */
U16 e_type; /* Object file type */
U16 e_machine; /* Architecture */
U32 e_version; /* Object file version */
U64 e_entry; /* Entry point virtual address */
U64 e_phoff; /* Program header table file offset */
U64 e_shoff; /* Section header table file offset */
U32 e_flags; /* Processor-specific flags */
U16 e_ehsize; /* ELF header size in bytes */
U16 e_phentsize; /* Program header table entry size */
U16 e_phnum; /* Program header table entry count */
U16 e_shentsize; /* Section header table entry size */
U16 e_shnum; /* Section header table entry count */
U16 e_shstrndx; /* Section header string table index */
};
class Elf64_Shdr {
U32 sh_name; /* Section name (string tbl index) */
U32 sh_type; /* Section type */
U64 sh_flags; /* Section flags */
U64 sh_addr; /* Section virtual addr at execution */
U64 sh_offset; /* Section file offset */
U64 sh_size; /* Section size in bytes */
U32 sh_link; /* Link to another section */
U32 sh_info; /* Additional section information */
U64 sh_addralign; /* Section alignment */
U64 sh_entsize; /* Entry size if section holds table */
};
class Elf64_Sym {
U32 st_name; /* Symbol name (string tbl index) */
U8 st_info; /* Symbol type and binding */
U8 st_other; /* Symbol visibility */
U16 st_shndx; /* Section index */
U64 st_value; /* Symbol value */
U64 st_size; /* Symbol size */
};
class PLT_entry {
U8 pad[0x10];
};
class RELA_entry {
U64 r_offset;
U64 r_info;
I64 r_addend;
};
class Elf {
union {
U8 *u8;
Elf64_Ehdr *ehdr;
} I64 size;
U8 *dynstr;
Elf64_Sym *dynsym;
PLT_entry *plt;
RELA_entry *rela_dyn;
RELA_entry *rela_plt;
Elf64_Sym *strtab;
Elf64_Sym *symtab;
I64 rela_dyn_size;
I64 rela_plt_size;
I64 strtab_size;
I64 symtab_size;
};
U0 (*_start)();
U0 unimplemented_symbol() {
I32 s = 0xDEADF00D;
"Unimplemented symbol: %s\n", s;
while (1)
Sleep(1);
}
Bool is_valid_elf(Elf *elf) {
Bool res = TRUE;
if (MemCompare(elf->u8 + 1, "ELF", 3)) {
debug_print("Invalid signature (not ELF).\n");
res = FALSE;
}
if (elf->ehdr->e_type != ET_EXEC && elf->ehdr->e_type != ET_DYN) {
debug_print("Invalid object file type.\n");
res = FALSE;
}
if (elf->ehdr->e_machine != EM_X86_64) {
debug_print("Invalid architecture.\n");
res = FALSE;
}
return res;
}
U0 find_value(U8 *value) {
U64 addr = 0x0;
while (addr < 0x2000000) {
if (!MemCompare(addr, value, StrLen(value))) {
"found at 0x%08x\n", addr;
return;
}
addr++;
}
"not found\n";
}
U0 process_elf_section_header_table(Elf *elf) {
Elf64_Shdr *shdr = elf->u8 + elf->ehdr->e_shoff;
Elf64_Shdr *shdr_shstrtab = shdr + elf->ehdr->e_shstrndx;
U8 *shstrtab = elf->u8 + shdr_shstrtab->sh_offset;
I64 i = 0;
while (i < elf->ehdr->e_shnum) {
if (!StrCompare(shstrtab + shdr->sh_name, ".symtab")) {
debug_print("found symtab at 0x%08x, size = %d\n", shdr->sh_offset,
shdr->sh_size);
elf->symtab = elf->u8 + shdr->sh_offset;
elf->symtab_size = shdr->sh_size;
}
if (!StrCompare(shstrtab + shdr->sh_name, ".strtab")) {
debug_print("found strtab at 0x%08x, size = %d\n", shdr->sh_offset,
shdr->sh_size);
elf->strtab = elf->u8 + shdr->sh_offset;
elf->strtab_size = shdr->sh_size;
}
if (shdr->sh_addr) {
MemCopy(shdr->sh_addr, elf->u8 + shdr->sh_offset, shdr->sh_size);
if (!StrCompare(shstrtab + shdr->sh_name, ".dynstr"))
elf->dynstr = shdr->sh_addr;
if (!StrCompare(shstrtab + shdr->sh_name, ".dynsym"))
elf->dynsym = shdr->sh_addr;
if (!StrCompare(shstrtab + shdr->sh_name, ".plt"))
elf->plt = shdr->sh_addr;
if (!StrCompare(shstrtab + shdr->sh_name, ".rela.dyn")) {
elf->rela_dyn = shdr->sh_addr;
elf->rela_dyn_size = shdr->sh_size / shdr->sh_entsize;
}
if (!StrCompare(shstrtab + shdr->sh_name, ".rela.plt")) {
elf->rela_plt = shdr->sh_addr;
elf->rela_plt_size = shdr->sh_size / shdr->sh_entsize;
}
debug_print(
"MemCopy section '%s' to physical address 0x%06x, size = %d bytes\n",
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
if (!StrCompare(shstrtab + shdr->sh_name, ".bss")) {
MemSet(shdr->sh_addr, NULL, shdr->sh_size);
debug_print("MemSet section '%s' at physical address 0x%06x to NULL, "
"size = %d bytes\n",
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
}
}
shdr++;
i++;
}
}
U0 process_elf_rela_dyn_entries(Elf *elf) {
I64 i;
U8 *entry_name;
RELA_entry *rela_dyn = elf->rela_dyn;
for (i = 0; i < elf->rela_dyn_size; i++) {
entry_name = elf->dynstr + elf->dynsym[(rela_dyn->r_info >> 32)].st_name;
debug_print("rela_dyn->r_offset = %08x\n", rela_dyn->r_offset);
debug_print("entry name = '%s'\n", entry_name);
if (!StrCompare(entry_name, "__libc_start_main")) {
*(rela_dyn->r_offset)(U64 *) = &_main;
debug_print("Set value for .rela.dyn entry '%s' to: &_main\n",
entry_name);
}
if (!StrCompare(entry_name, "stdin")) {
*(rela_dyn->r_offset)(U64 *) = 0;
debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 0);
}
if (!StrCompare(entry_name, "stdout")) {
*(rela_dyn->r_offset)(U64 *) = 1;
debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 1);
}
if (!StrCompare(entry_name, "stderr")) {
*(rela_dyn->r_offset)(U64 *) = 2;
debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 2);
}
rela_dyn++;
}
}
CHashClass *get_symbol_hash_entry(U8 *entry_name) {
I64 i;
CHashSrcSym *sym;
CHashTable *tbl = Fs->hash_table;
while (tbl) {
for (i = 0; i < tbl->mask; i++) {
sym = tbl->body[i];
while (sym) {
if (sym->type == HTT_CLASS)
if (!StrCompare(sym->str, entry_name))
return sym;
sym = sym->next;
}
}
tbl = tbl->next;
}
return NULL;
}
U0 process_elf_debug_symbols(Elf *elf) {
I64 i = 0;
I64 entry_bind;
U64 entry_name;
I64 entry_type;
CHashFun *hf;
CHashGlobalVar *hgv;
Elf64_Sym *symtab = elf->symtab;
entry_name = elf->strtab;
entry_name += symtab->st_name;
while (i < 253) {
entry_bind = symtab->st_info >> 4;
entry_type = symtab->st_info & 0xf;
switch (entry_type) {
case STT_OBJECT:
hgv = CAlloc(sizeof(CHashGlobalVar));
hgv->str = entry_name;
hgv->type = HTT_GLOBAL_VAR;
hgv->data_addr = symtab->st_value;
hgv->size = symtab->st_size;
// TempleOS reboots if I nest a switch table here, for some reason, so we
// have to do this dumb shit instead...
hgv->var_class = get_symbol_hash_entry("U32");
if (hgv->size == 1)
hgv->var_class = get_symbol_hash_entry("U8");
if (hgv->size == 2)
hgv->var_class = get_symbol_hash_entry("U16");
HashAdd(hgv, Fs->hash_table);
debug_print(
"Add global variable '%s' to hash table, addr = 0x%08x, size = %d\n",
entry_name, symtab->st_value, symtab->st_size);
break;
case STT_FUNC:
hf = CAlloc(sizeof(CHashFun));
hf->str = entry_name;
hf->type = HTT_FUN;
hf->exe_addr = symtab->st_value;
hf->size = symtab->st_size;
HashAdd(hf, Fs->hash_table);
debug_print("Add function '%s' to hash table, addr = 0x%08x, size = %d\n",
entry_name, symtab->st_value, symtab->st_size);
break;
}
symtab++;
i++;
entry_name = elf->strtab;
entry_name += symtab->st_name;
}
}
U64 get_symbol_address(U8 *entry_name) {
I64 i;
CHashSrcSym *sym;
CHashTable *tbl = Fs->hash_table;
while (tbl) {
for (i = 0; i < tbl->mask; i++) {
sym = tbl->body[i];
while (sym) {
if (sym->type == HTT_GLOBAL_VAR)
if (!StrCompare(sym->str, entry_name))
return sym(CHashGlobalVar *)->data_addr;
if (sym->type == HTT_FUN)
if (!StrCompare(sym->str, entry_name))
return sym(CHashFun *)->exe_addr;
sym = sym->next;
}
}
tbl = tbl->next;
}
return NULL;
}
U0 process_debug_patches(Elf *elf) { no_warn elf; }
U0 process_elf_rela_plt_entries(Elf *elf) {
I64 i;
U32 handler;
U32 *patch;
U8 *entry_name;
Bool symbol_exists;
PLT_entry *plt = elf->plt;
RELA_entry *rela_plt = elf->rela_plt;
plt++;
for (i = 0; i < elf->rela_plt_size; i++) {
symbol_exists = FALSE;
entry_name = elf->dynstr + elf->dynsym[(rela_plt->r_info >> 32)].st_name;
handler = MAlloc(sizeof(unimplemented_symbol), Fs->code_heap);
MemCopy(handler, &unimplemented_symbol, sizeof(unimplemented_symbol));
patch = handler + 0x0A;
*patch = entry_name;
PatchJmpRel32(plt, handler);
PatchCallRel32(handler + 0x16, &PrintErr);
PatchCallRel32(handler + 0x21, &_exit);
if (!StrCompare(entry_name, "__libc_start_main")) {
symbol_exists = TRUE;
PatchJmpRel32(plt, &_main);
debug_print("Set value for .rela.plt entry '%s' to &_main\n", entry_name);
}
if (get_symbol_address(entry_name)) {
symbol_exists = TRUE;
PatchJmpRel32(plt, get_symbol_address(entry_name));
debug_print("Set value for .rela.plt entry '%s' to &%s\n", entry_name,
entry_name);
}
if (!symbol_exists)
debug_print(
"Set value for .rela.plt entry '%s' to &unimplemented_symbol\n",
entry_name);
rela_plt++;
plt++;
}
}
U0 load_elf(...) {
if (argc < 1) {
PrintErr("Not enough arguments.\n");
return;
}
if (!FileFind(argv[0])) {
PrintErr("File not found: %s\n", argv[0]);
return;
}
Elf elf;
elf.u8 = FileRead(argv[0], &elf.size);
debug_print("Load file '%s', size = %d bytes\n", argv[0], elf.size);
if (!is_valid_elf(&elf)) {
PrintErr("File is not a valid ELF x86-64 executable.\n");
return;
}
process_elf_section_header_table(&elf);
process_elf_rela_dyn_entries(&elf);
process_elf_rela_plt_entries(&elf);
process_elf_debug_symbols(&elf);
_start = elf.ehdr->e_entry;
elf_argc = argc;
elf_argv = argv;
process_debug_patches(&elf);
//_start();
}

151
src/Home/Tracker/Lib/LibC.ZC Executable file
View file

@ -0,0 +1,151 @@
U64 find_u32_in_memory(U64 offset, U32 value) {
I64 i = 0;
while (MemCompare(offset + i, &value, 4))
i++;
return offset + i;
}
#define PUSH_SYSV_REGS \
asm {PUSH RCX PUSH RDX PUSH RBX PUSH RBP PUSH RSI PUSH RDI PUSH R8 PUSH R9 PUSH \
R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15}
#define POP_SYSV_REGS \
asm {POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP RDI POP \
RSI POP RBP POP RBX POP RDX POP RCX}
#define MOV_ANS_RAX asm {MOV [&ans], RAX}
#define MOV_P0_RDI asm {MOV [&p0], RDI}
#define MOV_P1_RSI asm {MOV [&p1], RSI}
#define MOV_P2_RDX asm {MOV [&p2], RDX}
#define MOV_P3_RCX asm {MOV [&p3], RCX}
#define MOV_P4_R8 asm {MOV [&p4], R8}
#define MOV_P5_R9 asm {MOV [&p5], R9}
#define GET_SYSV_ARGS \
MOV_P0_RDI MOV_P1_RSI MOV_P2_RDX MOV_P3_RCX MOV_P4_R8 MOV_P5_R9
I64 p0, p1, p2, p3, p4, p5;
I64 elf_argc;
U8 **elf_argv;
#define stdin 0
#define stdout 1
#define stderr 2
asm {
_ELF_CALL::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG2[RBP]
MOV RSI,U64 SF_ARG3[RBP]
TEST RAX,RAX
JZ @@05
CALL RAX
@@05: POP RBP
RET1 8
}
U0 _main() {
MOV_P0_RDI
CallInd(_ELF_CALL, p0, elf_argc, elf_argv);
MOV_ANS_RAX
throw('end', TRUE);
}
U0 _exit() {
MOV_ANS_RAX
throw('end', TRUE);
}
U0 free() {
PUSH_SYSV_REGS
GET_SYSV_ARGS
debug_print("called free(0x%08x)\n", p0);
Free(p0);
POP_SYSV_REGS
}
U64 @malloc(I64 size) {
U64 ptr = NULL;
ptr = MAlloc(p0);
debug_print("malloc(%d), result: 0x%08x\n", size, ptr);
return ptr;
}
U0 malloc() {
PUSH_SYSV_REGS
GET_SYSV_ARGS
debug_print("called: malloc(%d)\n", p0);
@malloc(p0);
POP_SYSV_REGS
}
U0 memcpy() {
PUSH_SYSV_REGS
GET_SYSV_ARGS
debug_print("called: memcpy(0x%08x, 0x%08x, %d)\n", p0, p1, p2);
MemCopy(p0, p1, p2);
POP_SYSV_REGS
}
U8 *@memmove(U8 *dest, U8 *src, I64 n) {
I64 i;
U8 *from = src;
U8 *to = dest;
if (from == to || n == 0)
return dest;
if (to > from && to - from < n) {
/* to overlaps with from */
/* <from......> */
/* <to........> */
/* copy in reverse, to avoid overwriting from */
for (i = n - 1; i >= 0; i--)
to[i] = from[i];
return dest;
}
if (from > to && from - to < n) {
/* to overlaps with from */
/* <from......> */
/* <to........> */
/* copy forwards, to avoid overwriting from */
for (i = 0; i < n; i++)
to[i] = from[i];
return dest;
}
MemCopy(dest, src, n);
return dest;
}
U0 memmove() {
PUSH_SYSV_REGS
GET_SYSV_ARGS
debug_print("called: memmove(0x%08x, 0x%08x, %d)\n", p0, p1, p2);
@memmove(p0, p1, p2);
POP_SYSV_REGS
}
U0 memset() {
PUSH_SYSV_REGS
GET_SYSV_ARGS
debug_print("called: memset(0x%08x, %d, %d)\n", p0, p1, p2);
MemSet(p0, p1, p2);
POP_SYSV_REGS
}
U8 *@realloc(U8 *ptr, I64 size) {
U8 *new;
if (!ptr) {
new = MAlloc(size);
} else {
new = MAlloc(size);
MemCopy(new, ptr, size);
Free(ptr);
}
return new;
}
U0 realloc() {
PUSH_SYSV_REGS
GET_SYSV_ARGS
debug_print("called: realloc(0x%08x, %d)\n", p0, p1);
@realloc(p0, p1);
POP_SYSV_REGS
}

View file

@ -0,0 +1,16 @@
asm {
GCC_FUN_ADDR::
DU64 0;
HOLYC_ARG1::
DU64 0;
HOLYC_ARG2::
DU64 0;
HOLYC_ARG3::
DU64 0;
HOLYC_ARG4::
DU64 0;
HOLYC_ARG5::
DU64 0;
HOLYC_ARG6::
DU64 0;
}

30
src/Home/Tracker/Lib/Misc.ZC Executable file
View file

@ -0,0 +1,30 @@
I64 Cond(Bool cond, I64 true, I64 false) {
if (cond)
return true;
return false;
}
U0 PatchCallRel32(U32 from, U32 to) {
*(from(U8 *)) = 0xE8;
*((from + 1)(I32 *)) = to - from - 5;
}
U0 PatchJmpRel32(U32 from, U32 to) {
*(from(U8 *)) = 0xE9;
*((from + 1)(I32 *)) = to - from - 5;
}
U0 EnableSSE() {
asm
{
MOV_EAX_CR0
AND AX, 0xFFFB // clear coprocessor emulation CR0.EM
OR AX, 0x2 // set coprocessor monitoring CR0.MP
MOV_CR0_EAX
MOV_EAX_CR4
OR AX, 3 << 9 // set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
MOV_CR4_EAX
}
}
EnableSSE;

98
src/Home/Tracker/Lib/Pci.ZC Executable file
View file

@ -0,0 +1,98 @@
#define PCI_INTH_MAX 16
U64 pci_int_handlers[PCI_INTH_MAX];
class CPCIInfo
{
U16 vendor_id;
U16 device_id;
U16 command;
U16 status;
U32 _class;
U32 bar[6];
U32 cap_pointer;
};
class CPCICapability
{
U8 cap_vndr; /*Generic PCI field: PCI_CAP_ID_VNDR */
U8 cap_next; /*Generic PCI field: next ptr. */
U8 cap_len; /*Generic PCI field: capability length */
U8 cfg_type; /*Identifies the structure. */
U8 bar; /*Where to find it. */
U8 padding[3]; /*Pad to full dword. */
U32 offset; /*Offset within bar. */
U32 length; /*Length of the structure, in bytes. */
};
U0 PCIInfoGet(I64 i, CPCIInfo *pci)
{
I64 j;
pci->vendor_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) &0xFFFF;
pci->device_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) >> 16;
pci->command = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) &0xFFFF;
pci->status = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) >> 16;
pci->_class = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x8) >> 24;
for (j = 0; j < 6; j++)
pci->bar[j] = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x10 + (0x04 * j));
}
U0 PCIGetCapability(I64 i, CPCICapability *cap, I64 idx)
{
I64 base = 0x40 + (idx * 16);
U32 u32;
u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base);
cap->cap_vndr = u32.u8[0];
cap->cap_next = u32.u8[1];
cap->cap_len = u32.u8[2];
cap->cfg_type = u32.u8[3];
u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x04);
cap->bar = u32.u8[0];
cap->offset = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x08);
cap->length = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x0c);
}
U0 PCIInterruptReroute(I64 base, I64 cpu)
{
I64 i;
U8 *da = dev.uncached_alias + IOAPIC_REG;
U32 *_d = dev.uncached_alias + IOAPIC_DATA;
for (i = 0; i < 4; i++)
{
*da = IOREDTAB + i * 2 + 1;
*_d = dev.mp_apic_ids[cpu] << 24;
*da = IOREDTAB + i * 2;
*_d = 0x4000 + base + i;
}
}
I64 PCIInterruptHandlerRegister(U64 handler)
{
if (!handler)
return -1;
I64 i = 0;
while (pci_int_handlers[i])
i++;
if (i > PCI_INTH_MAX - 1)
return -1;
pci_int_handlers[i] = handler;
return 0;
}
interrupt U0 PCIInterruptHandler()
{
I64 i;
for (i = 0; i < PCI_INTH_MAX; i++)
if (pci_int_handlers[i])
Call(pci_int_handlers[i]);
*(dev.uncached_alias + LAPIC_EOI)(U32 *) = 0;
}
MemSet(&pci_int_handlers, NULL, sizeof(U64) * PCI_INTH_MAX);
// IntEntrySet(0x40, &PCIInterruptHandler, IDTET_IRQ);
// IntEntrySet(0x41, &PCIInterruptHandler, IDTET_IRQ);
// IntEntrySet(0x42, &PCIInterruptHandler, IDTET_IRQ);
// IntEntrySet(0x43, &PCIInterruptHandler, IDTET_IRQ);
//PCIInterruptReroute(0x40, 0);

32
src/Home/Tracker/Load.ZC Executable file
View file

@ -0,0 +1,32 @@
#define include_noreindex #include
include_noreindex "Lib/Debug";
include_noreindex "Lib/Misc";
include_noreindex "Lib/Pci";
include_noreindex "Lib/AC97";
include_noreindex "Lib/LibC";
include_noreindex "Lib/LibHolyC";
include_noreindex "Lib/ELF64";
// load_elf("dr_mp3");
// include_noreindex "Lib/uPNG32";
// include_noreindex "Player32";
//include_noreindex "Lib/uPNG";
// include_noreindex "Player";
include_noreindex "Classes"
include_noreindex "MIDIHandling"
include_noreindex "WaveformGen"
// include_noreindex "UITracker"
include_noreindex "MusicTracker"
AutoComplete(0);
MusicTracker;
//InitPlayer;

View file

@ -0,0 +1,26 @@
// precalculated, takes more memory but less CPU
F64 midi_to_freq[128] = {
8.1758, 8.6620, 9.1770, 9.7227, 10.3009, 10.9134, 11.5623, 12.2499,
12.9783, 13.7500, 14.5676, 15.4339, 16.3516, 17.3239, 18.3540, 19.4454,
20.6017, 21.8268, 23.1247, 24.4997, 25.9565, 27.5000, 29.1352, 30.8677,
32.7032, 34.6478, 36.7081, 38.8909, 41.2034, 43.6535, 46.2493, 48.9994,
51.9131, 55.0000, 58.2705, 61.7354, 65.4064, 69.2957, 73.4162, 77.7817,
82.4069, 87.3071, 92.4986, 97.9989, 103.8262, 110.0000, 116.5409, 123.4708,
130.8128, 138.5913, 146.8324, 155.5635, 164.8138, 174.6141, 184.9972, 195.9977,
207.6523, 220.0000, 233.0819, 246.9417, 261.6256, 277.1826, 293.6648, 311.1270,
329.6276, 349.2282, 369.9944, 391.9954, 415.3047, 440.0000, 466.1638, 493.8833,
523.2511, 554.3653, 587.3295, 622.2540, 659.2551, 698.4565, 739.9888, 783.9909,
830.6094, 880.0000, 932.3275, 987.7666, 1046.5023, 1108.7305, 1174.6591, 1244.5079,
1318.5102, 1396.9129, 1479.9777, 1567.9817, 1661.2188, 1760.0000, 1864.6550, 1975.5332,
2093.0045, 2217.4610, 2349.3181, 2489.0159, 2637.0205, 2793.8259, 2959.9554, 3135.9635,
3322.4376, 3520.0000, 3729.3101, 3951.0664, 4186.0090, 4434.9221, 4698.6363, 4978.0317,
5274.0410, 5587.6517, 5919.9108, 6271.9270, 6644.8752, 7040.0000, 7458.6202, 7902.1328,
8372.0181, 8869.8442, 9397.2726, 9956.0635, 10548.0820, 11175.3034, 11839.8215, 12543.8540
};
// slower cause uses CPU but takes less memory
F64 MidiToFreq(I64 note) {
// A4 (MIDI note 69) = 440 Hz, and there's a 2^(1/12) ratio between adjacent semitones.
return 440.0 * Pow(2.0, (note - 69.0) / 12.0);
}

View file

@ -0,0 +1,67 @@
#include "MIDIHandling"
#include "WaveformGen"
U0 AudioPlayNote(U8 note, U8 velocity) {
U32 buffer[44100]; // One second buffer at 44.1kHz sample rate.
F64 freq = MidiToFreq(note);
GenerateSineWave(buffer, SAMPLE_RATE, freq, velocity);
// Play the buffer using your AC97 driver:
AudioSFXPlay(buffer, 44100); // Assuming your AudioSFXPlay function can handle this
}
U0 EnterPattern(Pattern *pattern) {
I64 row, choice;
NoteCell *cell;
for (row = 0; row < TRACK_LENGTH; row++) {
cell = &pattern->cells[row];
Print("Enter note for row %d (0-127, 0 for none): ", row);
// cell->note = InU8;
// if (cell->note) {
// Print("Enter velocity for note (1-127): ");
// cell->velocity = InU8;
// }
}
}
U0 PlayPattern(Pattern *pattern) {
I64 row;
NoteCell *cell;
for (row = 0; row < TRACK_LENGTH; row++) {
cell = &pattern->cells[row];
if (cell->note) {
// Here, use your audio driver to play the note
// Assume a function AudioPlayNote(note, velocity) exists
AudioPlayNote(cell->note, cell->velocity);
}
Sleep(100); // Adjust for tempo
}
}
U0 MusicTracker() {
Song song;
// Clear(&song);
I64 choice, sc;
while (1) {
Print("\nMusic Tracker:\n");
Print("1. Enter Pattern\n");
Print("2. Play Pattern\n");
Print("3. Exit\n");
Print("Choice: ");
// choice = InU8;
choice = KeyGet(&sc);
switch (choice) {
case '1':
EnterPattern(&song.patterns[0]); // Only one pattern for simplicity
break;
case '2':
PlayPattern(&song.patterns[0]);
break;
case '3':
return;
default:
Print("Invalid choice.\n");
}
}
}

2
src/Home/Tracker/Run.ZC Executable file
View file

@ -0,0 +1,2 @@
Cd(__DIR__);;
#include "Load";

View file

@ -0,0 +1,82 @@
//--------------------------
// UI Functions
//--------------------------
Pattern myPattern;
myPattern.cells[0].note = 60; // Middle C
myPattern.cells[0].velocity = 100;
myPattern.cells[1].note = 62; // D
myPattern.cells[1].velocity = 100;
myPattern.cells[2].note = 64; // E
myPattern.cells[2].velocity = 100;
U64 InU64() {
U8 buf[32];
InStr(buf);
return ToI64(buf);
}
U0 DisplayMainUI() {
// Simple function to display a main menu
DocClear;
Print("\nMusic Tracker UI\n");
Print("1. Enter New Pattern\n");
Print("2. Play Pattern\n");
Print("3. Exit\n");
}
U0 HandleUserInput(Pattern *pattern) {
I64 choice, sc;
Print("Enter your choice: ");
// choice = InU64;
switch (KeyGet(&sc)) {
case '1':
EnterPattern(pattern);
break;
case '2':
PlayPattern(pattern);
break;
case '3':
Print("Goodbye!\n");
return; // Exit the loop and function
default:
Print("Invalid choice!\n");
break;
}
}
U0 ShowError(String msg) {
// Display error messages to the user
Print("Error: %s\n", msg);
}
U0 RenderPattern(Pattern *pattern) {
// For simplicity, just listing the notes in the pattern
for (I64 i = 0; i < TRACK_LENGTH; i++) {
Print("Row %d: Note %d, Velocity %d\n", i, pattern->cells[i].note, pattern->cells[i].velocity);
}
}
U0 SettingsMenu() {
// Display and handle the settings menu
// ...
}
//--------------------------
// Main UI Loop
//--------------------------
U0 UITrackerMainLoop(Pattern *pattern) {
while (1) {
DisplayMainUI();
HandleUserInput(pattern);
}
}
//--------------------------
// Entry point to run the UI
//--------------------------
UITrackerMainLoop(&myPattern);

View file

@ -0,0 +1,20 @@
U0 GenerateSineWave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
I64 i;
F64 amplitude = (ToF64(velocity) / 127.0) * 0x7FFF; // Adjust the amplitude based on velocity
F64 phase_increment = (2.0 * PI * freq) / 44100.0; // Assuming a sample rate of 44.1kHz
F64 phase = 0.0;
for (i = 0; i < length; i++) {
I16 sample_value = ToI64((Sin(phase) * amplitude)); // TODO should be ToI16
buffer[i] = (sample_value << 16) | (sample_value & 0xFFFF);
phase += phase_increment;
if (phase >= 2.0 * PI) phase -= 2.0 * PI;
}
}
// I64 sample_rate = SAMPLE_RATE // whatever your sample rate is
// for (I64 i = 0; i < sample_duration * sample_rate; i++) {
// sample = sin(2.0 * PI * freq * i / sample_rate);
// // Then send 'sample' to your audio buffer/output.
// }