mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-03-01 07:20:42 +01:00
Fix delay function, logs in 480i mode, clangd config
This commit is contained in:
parent
d5c1f0065b
commit
7e7db5b890
9
.clangd
Normal file
9
.clangd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# As clang/clangd's MIPS-I support is still experimental, some minor changes to
|
||||||
|
# the GCC arguments it picks up from CMake are required in order to prevent it
|
||||||
|
# from erroring out. Additionally, specifying the target architecture manually
|
||||||
|
# fixes some edge cases (such as CMake emitting 8.3 format paths on Windows and
|
||||||
|
# breaking clangd's target autodetection).
|
||||||
|
|
||||||
|
CompileFlags:
|
||||||
|
Add: [ --target=mipsel-none-elf, -march=mips1 ]
|
||||||
|
Remove: [ -march, -mno-llsc, -mdivide-breaks ]
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,6 +5,7 @@ desktop.ini
|
|||||||
|
|
||||||
# Do not include any built or cached files.
|
# Do not include any built or cached files.
|
||||||
build/
|
build/
|
||||||
|
.cache/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
@ -336,6 +336,7 @@ Parser *newCartParser(Dump &dump, FormatType formatType, uint8_t flags) {
|
|||||||
|
|
||||||
Parser *newCartParser(Dump &dump) {
|
Parser *newCartParser(Dump &dump) {
|
||||||
// Try all formats from the most complex one to the simplest.
|
// Try all formats from the most complex one to the simplest.
|
||||||
|
//for (auto &format : _KNOWN_FORMATS) {
|
||||||
for (int i = util::countOf(_KNOWN_FORMATS) - 1; i >= 0; i--) {
|
for (int i = util::countOf(_KNOWN_FORMATS) - 1; i >= 0; i--) {
|
||||||
auto &format = _KNOWN_FORMATS[i];
|
auto &format = _KNOWN_FORMATS[i];
|
||||||
Parser *parser = newCartParser(dump, format.format, format.flags);
|
Parser *parser = newCartParser(dump, format.format, format.flags);
|
||||||
|
@ -56,7 +56,7 @@ int _start(int argc, const char **argv) {
|
|||||||
// Set $gp to point to the middle of the .sdata/.sbss sections, ensuring
|
// Set $gp to point to the middle of the .sdata/.sbss sections, ensuring
|
||||||
// variables placed in those sections can be quickly accessed. See the
|
// variables placed in those sections can be quickly accessed. See the
|
||||||
// linker script for more details.
|
// linker script for more details.
|
||||||
__asm__ volatile("la $gp, _gp;");
|
__asm__ volatile("la $gp, _gp\n");
|
||||||
|
|
||||||
// Set all uninitialized variables to zero by clearing the BSS section.
|
// Set all uninitialized variables to zero by clearing the BSS section.
|
||||||
__builtin_memset(_bssStart, 0, _bssEnd - _bssStart);
|
__builtin_memset(_bssStart, 0, _bssEnd - _bssStart);
|
||||||
|
@ -19,24 +19,24 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define COP0_GET(reg, output) \
|
#define COP0_GET(reg, output) \
|
||||||
__asm__ volatile("mfc0 %0, $%1;" : "=r"(output) : "i"(reg))
|
__asm__ volatile("mfc0 %0, $%1\n" : "=r"(output) : "i"(reg))
|
||||||
#define COP0_SET(reg, input) \
|
#define COP0_SET(reg, input) \
|
||||||
__asm__ volatile("mtc0 %0, $%1;" :: "r"(input), "i"(reg))
|
__asm__ volatile("mtc0 %0, $%1\n" :: "r"(input), "i"(reg))
|
||||||
|
|
||||||
#define GTE_GET(reg, output) \
|
#define GTE_GET(reg, output) \
|
||||||
__asm__ volatile("mfc2 %0, $%1;" : "=r"(output) : "i"(reg))
|
__asm__ volatile("mfc2 %0, $%1\n" : "=r"(output) : "i"(reg))
|
||||||
#define GTE_SET(reg, input) \
|
#define GTE_SET(reg, input) \
|
||||||
__asm__ volatile("mtc2 %0, $%1;" :: "r"(input), "i"(reg))
|
__asm__ volatile("mtc2 %0, $%1\n" :: "r"(input), "i"(reg))
|
||||||
|
|
||||||
#define GTE_GETC(reg, output) \
|
#define GTE_GETC(reg, output) \
|
||||||
__asm__ volatile("cfc2 %0, $%1;" : "=r"(output) : "i"(reg))
|
__asm__ volatile("cfc2 %0, $%1\n" : "=r"(output) : "i"(reg))
|
||||||
#define GTE_SETC(reg, input) \
|
#define GTE_SETC(reg, input) \
|
||||||
__asm__ volatile("ctc2 %0, $%1;" :: "r"(input), "i"(reg))
|
__asm__ volatile("ctc2 %0, $%1\n" :: "r"(input), "i"(reg))
|
||||||
|
|
||||||
#define GTE_LOAD(reg, offset, ptr) \
|
#define GTE_LOAD(reg, offset, ptr) \
|
||||||
__asm__ volatile("lwc2 $%0, %1(%2);" :: "i"(reg), "i"(offset), "r"(ptr))
|
__asm__ volatile("lwc2 $%0, %1(%2)\n" :: "i"(reg), "i"(offset), "r"(ptr))
|
||||||
#define GTE_STORE(reg, offset, ptr) \
|
#define GTE_STORE(reg, offset, ptr) \
|
||||||
__asm__ volatile("swc2 $%0, %1(%2);" :: "i"(reg), "i"(offset), "r"(ptr) : "memory")
|
__asm__ volatile("swc2 $%0, %1(%2)\n" :: "i"(reg), "i"(offset), "r"(ptr) : "memory")
|
||||||
|
|
||||||
/* Coprocessor 0 */
|
/* Coprocessor 0 */
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ typedef struct {
|
|||||||
} GTEMatrix;
|
} GTEMatrix;
|
||||||
|
|
||||||
#define gte_command(cmd) \
|
#define gte_command(cmd) \
|
||||||
__asm__ volatile("nop; nop; cop2 %0;" :: "i"(cmd))
|
__asm__ volatile("nop\n" "nop\n" "cop2 %0\n" :: "i"(cmd))
|
||||||
|
|
||||||
/* GTE control registers */
|
/* GTE control registers */
|
||||||
|
|
||||||
|
@ -241,9 +241,9 @@ typedef enum {
|
|||||||
TIMER_CTRL_OVERFLOWED = 1 << 12
|
TIMER_CTRL_OVERFLOWED = 1 << 12
|
||||||
} TimerControlFlag;
|
} TimerControlFlag;
|
||||||
|
|
||||||
#define TIMER_VALUE(N) _MMIO32((IO_BASE | 0x100) + (16 * (N)))
|
#define TIMER_VALUE(N) _MMIO16((IO_BASE | 0x100) + (16 * (N)))
|
||||||
#define TIMER_CTRL(N) _MMIO32((IO_BASE | 0x104) + (16 * (N)))
|
#define TIMER_CTRL(N) _MMIO16((IO_BASE | 0x104) + (16 * (N)))
|
||||||
#define TIMER_RELOAD(N) _MMIO32((IO_BASE | 0x108) + (16 * (N)))
|
#define TIMER_RELOAD(N) _MMIO16((IO_BASE | 0x108) + (16 * (N)))
|
||||||
|
|
||||||
/* CD-ROM drive */
|
/* CD-ROM drive */
|
||||||
|
|
||||||
|
@ -89,22 +89,10 @@ void flushCache(void) {
|
|||||||
void softReset(void) {
|
void softReset(void) {
|
||||||
disableInterrupts();
|
disableInterrupts();
|
||||||
BIOS_ENTRY_POINT();
|
BIOS_ENTRY_POINT();
|
||||||
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IRQ acknowledgement and blocking delay */
|
/* IRQ acknowledgement */
|
||||||
|
|
||||||
void delayMicroseconds(int us) {
|
|
||||||
// 1 us = 33.8688 cycles = 17 loop iterations (2 cycles per iteration)
|
|
||||||
us *= (F_CPU + 1000000) / 2000000;
|
|
||||||
|
|
||||||
__asm__ volatile(
|
|
||||||
".set noreorder;"
|
|
||||||
"bgtz %0, .;"
|
|
||||||
"addiu %0, -1;"
|
|
||||||
".set reorder;"
|
|
||||||
: "=r"(us) : "r"(us)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool acknowledgeInterrupt(IRQChannel irq) {
|
bool acknowledgeInterrupt(IRQChannel irq) {
|
||||||
if (IRQ_STAT & (1 << irq)) {
|
if (IRQ_STAT & (1 << irq)) {
|
||||||
@ -116,22 +104,22 @@ bool acknowledgeInterrupt(IRQChannel irq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool waitForInterrupt(IRQChannel irq, int timeout) {
|
bool waitForInterrupt(IRQChannel irq, int timeout) {
|
||||||
for (; timeout > 0; timeout--) {
|
for (; timeout > 0; timeout -= 10) {
|
||||||
if (acknowledgeInterrupt(irq))
|
if (acknowledgeInterrupt(irq))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
delayMicroseconds(1);
|
delayMicroseconds(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool waitForDMATransfer(DMAChannel dma, int timeout) {
|
bool waitForDMATransfer(DMAChannel dma, int timeout) {
|
||||||
for (; timeout > 0; timeout--) {
|
for (; timeout > 0; timeout -= 10) {
|
||||||
if (!(DMA_CHCR(dma) & DMA_CHCR_ENABLE))
|
if (!(DMA_CHCR(dma) & DMA_CHCR_ENABLE))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
delayMicroseconds(1);
|
delayMicroseconds(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -136,13 +136,24 @@ void softReset(void);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Blocks for (roughly) the specified number of microseconds. This
|
* @brief Blocks for (roughly) the specified number of microseconds. This
|
||||||
* function does not rely on a hardware timer, so interrupts may throw off
|
* function will reset hardware timer 2 and use it for timing. Disabling
|
||||||
* timings if not explicitly disabled prior to calling delayMicroseconds().
|
* interrupts prior to calling delayMicroseconds() is highly recommended to
|
||||||
|
* prevent jitter, but not strictly necessary unless the interrupt handler
|
||||||
|
* accesses timer 2.
|
||||||
*
|
*
|
||||||
* @param time
|
* @param time
|
||||||
*/
|
*/
|
||||||
void delayMicroseconds(int time);
|
void delayMicroseconds(int time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Blocks for (roughly) the specified number of microseconds. This
|
||||||
|
* function does not rely on a hardware timer, so interrupts may throw off
|
||||||
|
* timings if not explicitly disabled prior to calling delayMicrosecondsBusy().
|
||||||
|
*
|
||||||
|
* @param time
|
||||||
|
*/
|
||||||
|
void delayMicrosecondsBusy(int time);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if the specified interrupt was fired but not yet acknowledged;
|
* @brief Checks if the specified interrupt was fired but not yet acknowledged;
|
||||||
* if so, acknowledges it and returns true. This function can be used in a
|
* if so, acknowledges it and returns true. This function can be used in a
|
||||||
@ -162,9 +173,9 @@ bool acknowledgeInterrupt(IRQChannel irq);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Waits for the specified interrupt to be fired for up to the specified
|
* @brief Waits for the specified interrupt to be fired for up to the specified
|
||||||
* number of microseconds. This function will work with interrupts that are not
|
* number of microseconds (with 10 us granularity). This function will work with
|
||||||
* explicitly enabled in the IRQ_MASK register, but will *not* work with
|
* interrupts that are not explicitly enabled in the IRQ_MASK register, but will
|
||||||
* interrupts that have been enabled if any callback set using
|
* *not* work with interrupts that have been enabled if any callback set using
|
||||||
* setInterruptHandler() acknowledges them.
|
* setInterruptHandler() acknowledges them.
|
||||||
*
|
*
|
||||||
* @param irq
|
* @param irq
|
||||||
@ -175,7 +186,7 @@ bool waitForInterrupt(IRQChannel irq, int timeout);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Waits for the specified DMA channel to finish any ongoing transfer for
|
* @brief Waits for the specified DMA channel to finish any ongoing transfer for
|
||||||
* up to the specified number of microseconds.
|
* up to the specified number of microseconds (with 10 us granularity).
|
||||||
*
|
*
|
||||||
* @param dma
|
* @param dma
|
||||||
* @param timeout
|
* @param timeout
|
||||||
@ -207,7 +218,7 @@ static inline void switchThreadImmediate(Thread *thread) {
|
|||||||
switchThread(thread);
|
switchThread(thread);
|
||||||
|
|
||||||
// Execute a syscall to force the switch to happen.
|
// Execute a syscall to force the switch to happen.
|
||||||
__asm__ volatile("syscall 0;" ::: "memory");
|
__asm__ volatile("syscall 0\n" ::: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
.set noreorder
|
.set noreorder
|
||||||
.set noat
|
.set noat
|
||||||
|
|
||||||
|
## Exception handler
|
||||||
|
|
||||||
.set BADV, $8
|
.set BADV, $8
|
||||||
.set SR, $12
|
.set SR, $12
|
||||||
.set CAUSE, $13
|
.set CAUSE, $13
|
||||||
@ -179,3 +181,96 @@ _exceptionHandler:
|
|||||||
|
|
||||||
jr $k1
|
jr $k1
|
||||||
rfe
|
rfe
|
||||||
|
|
||||||
|
## Delay functions
|
||||||
|
|
||||||
|
.set IO_BASE, 0xbf801000
|
||||||
|
|
||||||
|
.set TIMER2_VALUE, IO_BASE | 0x120
|
||||||
|
.set TIMER2_CTRL, IO_BASE | 0x124
|
||||||
|
.set TIMER2_RELOAD, IO_BASE | 0x128
|
||||||
|
|
||||||
|
.section .text.delayMicroseconds, "ax", @progbits
|
||||||
|
.global delayMicroseconds
|
||||||
|
.type delayMicroseconds, @function
|
||||||
|
|
||||||
|
delayMicroseconds:
|
||||||
|
# Calculate the approximate number of CPU cycles that need to be burned,
|
||||||
|
# assuming a 33.8688 MHz clock (1 us = 33.8688 = ~33.875 cycles).
|
||||||
|
sll $a1, $a0, 8 # cycles = ((us * 271) + 4) / 8
|
||||||
|
sll $a2, $a0, 4
|
||||||
|
addu $a1, $a2
|
||||||
|
subu $a1, $a0
|
||||||
|
addiu $a1, 4
|
||||||
|
sra $a0, $a1, 3
|
||||||
|
|
||||||
|
# Compensate for the overhead of calculating the cycle count, entering the
|
||||||
|
# loop and returning.
|
||||||
|
addiu $a0, -(6 + 1 + 2 + 3 + 2)
|
||||||
|
|
||||||
|
# Reset timer 2 to its default setting of counting system clock edges.
|
||||||
|
lui $v1, %hi(IO_BASE)
|
||||||
|
sh $0, %lo(TIMER2_CTRL)($v1) # TIMER2_CTRL = 0
|
||||||
|
|
||||||
|
# Wait for up to 0xff00 cycles at a time (resetting the timer and waiting
|
||||||
|
# for it to count up each time), as the counter is only 16 bits wide. We
|
||||||
|
# have to wait 0xff00 cycles rather than 0x10000 since the counter wraps
|
||||||
|
# around rather than saturating on overflow.
|
||||||
|
li $a1, 0xff00
|
||||||
|
slt $v0, $a1, $a0
|
||||||
|
#beqz $v0, .LshortDelay
|
||||||
|
#nop
|
||||||
|
beqz $v0, .LskipLongDelay
|
||||||
|
|
||||||
|
.LlongDelay: # for (; cycles > 0xff00; cycles -= 0xff00)
|
||||||
|
sh $0, %lo(TIMER2_VALUE)($v1) # TIMER2_VALUE = 0
|
||||||
|
li $v0, 0
|
||||||
|
|
||||||
|
.LlongDelayLoop: # while (TIMER2_VALUE < 0xff00);
|
||||||
|
nop
|
||||||
|
slt $v0, $v0, $a1
|
||||||
|
bnez $v0, .LlongDelayLoop
|
||||||
|
lhu $v0, %lo(TIMER2_VALUE)($v1)
|
||||||
|
|
||||||
|
slt $v0, $a1, $a0
|
||||||
|
bnez $v0, .LlongDelay
|
||||||
|
subu $a0, $a1
|
||||||
|
|
||||||
|
.LshortDelay:
|
||||||
|
# Run the last busy loop once less than 0xff00 cycles are remaining.
|
||||||
|
sh $0, %lo(TIMER2_VALUE)($v1) # TIMER2_VALUE = 0
|
||||||
|
.LskipLongDelay:
|
||||||
|
li $v0, 0
|
||||||
|
|
||||||
|
.LshortDelayLoop: # while (TIMER2_VALUE < cycles);
|
||||||
|
nop
|
||||||
|
slt $v0, $v0, $a0
|
||||||
|
bnez $v0, .LshortDelayLoop
|
||||||
|
lhu $v0, %lo(TIMER2_VALUE)($v1)
|
||||||
|
|
||||||
|
jr $ra
|
||||||
|
nop
|
||||||
|
|
||||||
|
.section .text.delayMicrosecondsBusy, "ax", @progbits
|
||||||
|
.global delayMicrosecondsBusy
|
||||||
|
.type delayMicrosecondsBusy, @function
|
||||||
|
|
||||||
|
delayMicrosecondsBusy:
|
||||||
|
# Calculate the approximate number of CPU cycles that need to be burned,
|
||||||
|
# assuming a 33.8688 MHz clock (1 us = 33.8688 = ~33.875 cycles).
|
||||||
|
sll $a1, $a0, 8 # cycles = ((us * 271) + 4) / 8
|
||||||
|
sll $a2, $a0, 4
|
||||||
|
addu $a1, $a2
|
||||||
|
subu $a1, $a0
|
||||||
|
addiu $a1, 4
|
||||||
|
sra $a0, $a1, 3
|
||||||
|
|
||||||
|
# Compensate for the overhead of calculating the cycle count and returning.
|
||||||
|
addiu $a0, -(6 + 1 + 2)
|
||||||
|
|
||||||
|
.Lloop: # while (cycles > 0) cycles -= 2
|
||||||
|
bgtz $a0, .Lloop
|
||||||
|
addiu $a0, -2
|
||||||
|
|
||||||
|
jr $ra
|
||||||
|
nop
|
||||||
|
@ -42,8 +42,8 @@ Logger::Logger(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Logger::clear(void) {
|
void Logger::clear(void) {
|
||||||
for (int i = 0; i < MAX_LOG_LINES; i++)
|
for (auto line : _lines)
|
||||||
_lines[i][0] = 0;
|
line[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::log(const char *format, ...) {
|
void Logger::log(const char *format, ...) {
|
||||||
@ -114,8 +114,10 @@ uint32_t zipCRC32(const uint8_t *data, size_t length, uint32_t crc) {
|
|||||||
crc = ~crc;
|
crc = ~crc;
|
||||||
|
|
||||||
for (; length; length--) {
|
for (; length; length--) {
|
||||||
|
uint32_t temp = crc;
|
||||||
|
|
||||||
crc >>= 8;
|
crc >>= 8;
|
||||||
crc ^= table[(crc ^ *(data++)) & 0xff];
|
crc ^= table[(temp ^ *(data++)) & 0xff];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ~crc;
|
return ~crc;
|
||||||
|
@ -224,7 +224,7 @@ public:
|
|||||||
/* Logger (basically a ring buffer of lines) */
|
/* Logger (basically a ring buffer of lines) */
|
||||||
|
|
||||||
static constexpr int MAX_LOG_LINE_LENGTH = 128;
|
static constexpr int MAX_LOG_LINE_LENGTH = 128;
|
||||||
static constexpr int MAX_LOG_LINES = 32;
|
static constexpr int MAX_LOG_LINES = 64;
|
||||||
|
|
||||||
class Logger {
|
class Logger {
|
||||||
private:
|
private:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user