joybus rtc fully working with writes

This commit is contained in:
Polprzewodnikowy 2021-09-08 01:11:34 +02:00
parent 3ab5b7b6c8
commit ef205d218a
7 changed files with 215 additions and 21 deletions

View File

@ -60,7 +60,7 @@ module n64_flashram (
if (write_buffer_wmask[0]) high_buffer <= bus.wdata; if (write_buffer_wmask[0]) high_buffer <= bus.wdata;
end end
always @(posedge sys.clk) begin always_ff @(posedge sys.clk) begin
flashram.rdata <= write_buffer[flashram.address]; flashram.rdata <= write_buffer[flashram.address];
if (write_buffer_wmask[1]) write_buffer[bus.address[6:2]] <= {high_buffer, bus.wdata}; if (write_buffer_wmask[1]) write_buffer[bus.address[6:2]] <= {high_buffer, bus.wdata};
end end

View File

@ -30,6 +30,7 @@ void process_cfg (void);
void process_flashram (void); void process_flashram (void);
void process_si (void); void process_si (void);
void process_rtc (void); void process_rtc (void);
void process_uart (void);
bool debug_decide (uint32_t *args); bool debug_decide (uint32_t *args);
@ -45,19 +46,14 @@ void main (void) {
usb_flush_rx(); usb_flush_rx();
usb_flush_tx(); usb_flush_tx();
si_reset(); si_reset();
i2c_stop();
cfg_set_sdram_switch(true); cfg_set_sdram_switch(true);
cfg_set_save_type(CFG_SAVE_TYPE_NONE); cfg_set_save_type(CFG_SAVE_TYPE_NONE);
cfg_set_dd_offset(CFG_DEFAULT_DD_OFFSET); cfg_set_dd_offset(CFG_DEFAULT_DD_OFFSET);
cfg_set_cpu_ready(true); cfg_set_cpu_ready(true);
current_time[0] = 0x10; print("App ready!\r\n");
current_time[1] = 0x30;
current_time[2] = 0x90;
current_time[3] = 0x06;
current_time[4] = 0x01;
current_time[5] = 0x09;
current_time[6] = 0x21;
while (1) { while (1) {
process_usb(); process_usb();
@ -65,6 +61,7 @@ void main (void) {
process_flashram(); process_flashram();
process_si(); process_si();
process_rtc(); process_rtc();
process_uart();
} }
} }
@ -238,7 +235,7 @@ void process_flashram (void) {
} }
void process_si (void) { void process_si (void) {
uint8_t rx_data[12]; uint8_t rx_data[10];
uint8_t tx_data[12]; uint8_t tx_data[12];
uint32_t *save_data; uint32_t *save_data;
uint32_t *data_offset; uint32_t *data_offset;
@ -288,13 +285,10 @@ void process_si (void) {
if (!rtc_running) { if (!rtc_running) {
tx_data[1] = SI_RTC_ST_MASK; tx_data[1] = SI_RTC_ST_MASK;
} }
} else if (rx_data[1] == 1) { } else if (rx_data[1] == 2) {
// Backup SRAM
} else {
for (size_t i = 0; i < 7; i++) { for (size_t i = 0; i < 7; i++) {
tx_data[i] = current_time[i]; tx_data[i] = current_time[i];
} }
tx_data[2] |= 0x80;
tx_data[7] = SI_RTC_CENTURY_20XX; tx_data[7] = SI_RTC_CENTURY_20XX;
} }
tx_data[8] = SI_RTC_STATUS(rtc_running); tx_data[8] = SI_RTC_STATUS(rtc_running);
@ -305,9 +299,7 @@ void process_si (void) {
if (rx_data[1] == 0) { if (rx_data[1] == 0) {
rtc_wp_bits = rx_data[2] & SI_RTC_WP_MASK; rtc_wp_bits = rx_data[2] & SI_RTC_WP_MASK;
rtc_running = (!(rx_data[3] & SI_RTC_ST_MASK)); rtc_running = (!(rx_data[3] & SI_RTC_ST_MASK));
} else if (rx_data[1] == 1) { } else if (rx_data[1] == 2) {
// Backup SRAM
} else {
for (size_t i = 0; i < 7; i++) { for (size_t i = 0; i < 7; i++) {
new_time[i] = rx_data[i + 2]; new_time[i] = rx_data[i + 2];
} }
@ -324,11 +316,142 @@ void process_si (void) {
} }
void process_rtc (void) { void process_rtc (void) {
static e_rtc_state_t state = RTC_STATE_READ;
static e_rtc_state_t next_state = RTC_STATE_READ;
static uint8_t phase = 0;
static uint8_t sub_phase = 0;
static uint8_t rtc_current_time[7];
static uint8_t rtc_new_time[7];
if (new_time_pending) { if (new_time_pending) {
new_time_pending = false;
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
current_time[i] = new_time[i]; current_time[i] = new_time[i];
} }
new_time_pending = false;
rtc_convert_from_n64(new_time, rtc_new_time);
rtc_new_time[RTC_RTCSEC] |= RTC_RTCSEC_ST;
rtc_new_time[RTC_RTCWKDAY] |= RTC_RTCWKDAY_VBAT;
next_state = RTC_STATE_WRITE;
}
// TODO: Rewrite this mess
if (!i2c_busy()) {
if (state == RTC_STATE_READ) {
switch (phase) {
case 0: phase++; i2c_start(); break;
case 1: phase++; i2c_begin_trx(RTC_ADDR, false); break;
case 2: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
case 3: phase++; i2c_start(); break;
case 4: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
case 5:
if (sub_phase > 0) {
rtc_current_time[sub_phase - 1] = i2c_get_data();
}
if (sub_phase < 7) {
i2c_begin_trx(0xFF, true);
}
if (sub_phase == 7) {
phase++;
sub_phase = 0;
if (next_state != RTC_STATE_WRITE) {
rtc_convert_to_n64(rtc_current_time, current_time);
}
break;
}
sub_phase++;
break;
case 6: phase = 0; i2c_stop(); state = next_state; break;
}
} else if (state == RTC_STATE_WRITE) {
switch (phase) {
case 0: phase++; break;
case 1: phase++; i2c_start(); break;
case 2: phase++; i2c_begin_trx(RTC_ADDR, false); break;
case 3: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
case 4: phase++; i2c_begin_trx(0x00, false); break;
case 5: phase++; i2c_stop(); break;
case 6: phase++; i2c_start(); break;
case 7: phase++; i2c_begin_trx(RTC_ADDR, false); break;
case 8: phase++; i2c_begin_trx(RTC_RTCWKDAY, false); break;
case 9: phase++; i2c_start(); break;
case 10: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
case 11: phase++; i2c_begin_trx(0xFF, false); break;
case 12: phase = (i2c_get_data() & RTC_RTCWKDAY_OSCRUN) ? 6 : 13; i2c_stop(); break;
case 13: phase++; i2c_start(); break;
case 14: phase++; i2c_begin_trx(RTC_ADDR, false); break;
case 15: phase++; i2c_begin_trx(RTC_RTCMIN, false); break;
case 16:
if (sub_phase < 6) {
i2c_begin_trx(rtc_new_time[RTC_RTCMIN + sub_phase], false);
sub_phase++;
} else {
phase++;
sub_phase = 0;
i2c_stop();
}
break;
case 17: phase++; i2c_start(); break;
case 18: phase++; i2c_begin_trx(RTC_ADDR, false); break;
case 19: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
case 20: phase++; i2c_begin_trx(rtc_new_time[RTC_RTCSEC], false); break;
case 21: phase++; i2c_stop(); break;
case 22: phase++; i2c_start(); break;
case 23: phase++; i2c_begin_trx(RTC_ADDR, false); break;
case 24: phase++; i2c_begin_trx(RTC_RTCWKDAY, false); break;
case 25: phase++; i2c_start(); break;
case 26: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
case 27: phase++; i2c_begin_trx(0xFF, false); break;
case 28:
if (i2c_get_data() & RTC_RTCWKDAY_OSCRUN) {
phase = 0;
state = RTC_STATE_READ;
next_state = RTC_STATE_READ;
} else {
phase = 22;
}
i2c_stop();
break;
}
} else {
state = RTC_STATE_READ;
phase = 0;
sub_phase = 0;
}
}
}
void process_uart (void) {
if (UART->SCR & USB_SCR_RXNE) {
char cmd = UART->DR;
switch (cmd) {
case '/':
print("Bootloader reset...\r\n");
reset_handler();
break;
case '\'':
print("App reset...\r\n");
app_handler();
break;
case 't':
print("Current time: ");
for (int i = 0; i < 7; i++) {
print_02hex(current_time[i]);
print(" ");
}
print("\r\n");
}
} }
} }

View File

@ -16,6 +16,11 @@ typedef enum {
USB_STATE_PC_TO_N64, USB_STATE_PC_TO_N64,
} e_usb_state_t; } e_usb_state_t;
typedef enum {
RTC_STATE_READ,
RTC_STATE_WRITE,
} e_rtc_state_t;
typedef enum { typedef enum {
DEBUG_WRITE_ADDRESS, DEBUG_WRITE_ADDRESS,
DEBUG_WRITE_LENGTH_START, DEBUG_WRITE_LENGTH_START,

View File

@ -323,9 +323,50 @@ uint8_t i2c_get_data (void) {
} }
// misc // RTC
const char hex_char_map[16] = { static const uint8_t rtc_bit_mask[7] = {
0b01111111,
0b01111111,
0b00111111,
0b00000111,
0b00111111,
0b00011111,
0b11111111
};
void rtc_sanitize_time_data (uint8_t *time_data) {
for (int i = 0; i < 7; i++) {
time_data[i] &= rtc_bit_mask[i];
}
}
void rtc_convert_to_n64 (uint8_t *rtc_data, uint8_t *n64_data) {
rtc_sanitize_time_data(rtc_data);
n64_data[0] = rtc_data[RTC_RTCSEC];
n64_data[1] = rtc_data[RTC_RTCMIN];
n64_data[2] = rtc_data[RTC_RTCHOUR] | 0x80;
n64_data[4] = rtc_data[RTC_RTCWKDAY] - 1;
n64_data[3] = rtc_data[RTC_RTCDATE];
n64_data[5] = rtc_data[RTC_RTCMTH];
n64_data[6] = rtc_data[RTC_RTCYEAR];
}
void rtc_convert_from_n64 (uint8_t *n64_data, uint8_t *rtc_data) {
rtc_data[RTC_RTCSEC] = n64_data[0];
rtc_data[RTC_RTCMIN] = n64_data[1];
rtc_data[RTC_RTCHOUR] = n64_data[2];
rtc_data[RTC_RTCWKDAY] = n64_data[4] + 1;
rtc_data[RTC_RTCDATE] = n64_data[3];
rtc_data[RTC_RTCMTH] = n64_data[5];
rtc_data[RTC_RTCYEAR] = n64_data[6];
rtc_sanitize_time_data(rtc_data);
}
// Misc
static const char hex_char_map[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
}; };

View File

@ -133,7 +133,28 @@ void i2c_begin_trx (uint8_t data, bool mack);
uint8_t i2c_get_data (void); uint8_t i2c_get_data (void);
// misc // RTC
#define RTC_ADDR (0xDE)
#define RTC_RTCSEC (0x00)
#define RTC_RTCMIN (0x01)
#define RTC_RTCHOUR (0x02)
#define RTC_RTCWKDAY (0x03)
#define RTC_RTCDATE (0x04)
#define RTC_RTCMTH (0x05)
#define RTC_RTCYEAR (0x06)
#define RTC_RTCSEC_ST (1 << 7)
#define RTC_RTCWKDAY_OSCRUN (1 << 5)
#define RTC_RTCWKDAY_VBAT (1 << 3)
void rtc_sanitize_time_data(uint8_t *time_data);
void rtc_convert_to_n64 (uint8_t *rtc_data, uint8_t *n64_data);
void rtc_convert_from_n64 (uint8_t *n64_data, uint8_t *rtc_data);
// Misc
void print (const char *text); void print (const char *text);
void print_02hex (uint8_t number); void print_02hex (uint8_t number);

View File

@ -5,7 +5,7 @@
#define BOOT_UART #define BOOT_UART
__attribute__ ((naked, section(".bootloader"))) int reset_handler (void) { __attribute__ ((naked, section(".bootloader"))) void reset_handler (void) {
register uint32_t length = 0; register uint32_t length = 0;
#if defined(BOOT_UART) #if defined(BOOT_UART)

View File

@ -156,4 +156,8 @@ typedef volatile struct si_regs {
#define SI_SCR_TX_LENGTH_BIT (16) #define SI_SCR_TX_LENGTH_BIT (16)
void reset_handler (void);
void app_handler (void);
#endif #endif