#include #include #include #include "shared_page.h" #include "state_page.h" #include "monitor_subroutines.h" #include "utility.h" #include "mem_map.h" #include "mem_registers.h" #include "disk2.h" #include "dos_floppy.h" // External initialization requirements #pragma require __data_initialization_needed // Require the exported function table to be present //#pragma require __exported_func_table #define DEFAULT_DRIVE_CONTROLLER_OFFSET 0x10 static uint8_t *module_page = (uint8_t*)MODULE_PAGE; static shared_page_data * shared_page = (shared_page_data*)SHARED_PAGE; #define FILE_LIST_LEN 6 #define FNAME_LEN 6 #define STATE_FILE_IDX 1 #define AUTOLOAD_FILES 3 // Autoload the first 3 files // We'll limit ourselves to files with a name of max 5 chars, to save some memory static const uint8_t file_table[FILE_LIST_LEN][FNAME_LEN] = { { 0x80 | 'L', 0x80 | 'O', 0x80 | 'A', 0x80 | 'D', 0x80 | 'S', 0x00}, // LOADS (this is not an executable, but will be used to show the loading screen). { 0x80 | 'S', 0x80 | 'T', 0x80 | 'A', 0x80 | 'T', 0x80 | 'E', 0x00}, // STATE (this is not an executable, but will be used to save/load the game and scores). { 0x80 | 'I', 0x80 | 'N', 0x80 | 'T', 0x80 | 'R', 0x80 | 'O', 0x00}, // INTRO (this executable will show the initial presentation picture) { 0x80 | 'D', 0x80 | 'L', 0x80 | 'O', 0x80 | 'G', 0xA0, 0x00}, // DLOG (startup, win, lose dialogs) { 0x80 | 'G', 0x80 | 'A', 0x80 | 'M', 0x80 | 'E', 0xA0, 0x00}, // GAME (the actual game) { 0x80 | 'D', 0x80 | 'E', 0x80 | 'M', 0x80 | 'O', 0xA0, 0x00}, // DEMO (automatic demo) }; static uint8_t file_trksec[FILE_LIST_LEN][2]; // This will hold track/sector for initial ts list sector for every one of the listed files. Populated at startup. static uint16_t file_load_address[FILE_LIST_LEN] = { // This will hold the load address for the files DISPLAY_PAGE_1, STATE_PAGE, MODULE_PAGE, MODULE_PAGE, MODULE_PAGE, MODULE_PAGE, }; static void init(void); static void init_floppy_data(uint8_t *cur_trk, uint8_t *cur_file); static uint8_t fill_trksec_list(uint8_t* cur_trk); // Low level initialization static void init(void) { POKE(P3_PWRDUP, 0); // Dirty the value checked by the reset vector PEEK(IO_ROMSEL); // Make sure the ROM is selected PEEK(DISPLAY_PAGE_1); // Select display page 1 PEEK(IO_DISPLAY_BW); // Disable colors // Generate the decoding table dii_generate_6bit_decoding_mapping_table((uint8_t*)DECODING_MAPPING_TABLE_DEFAULT_ADDRESS); // Generate the encoding table dii_generate_6bit_encoding_mapping_table((uint8_t*)ENCODING_MAPPING_TABLE_DEFAULT_ADDRESS); } static uint8_t fill_trksec_list(uint8_t* cur_trk) { uint8_t file_counter = 0; for(uint8_t file_idx = 0; file_idx < FILE_LIST_LEN; file_idx++) { FDE* f_desc = df_search_file(DEFAULT_DRIVE_CONTROLLER_OFFSET, file_table[file_idx], cur_trk); if(f_desc) { file_trksec[file_idx][0] = f_desc->tsl_trk; file_trksec[file_idx][1] = f_desc->tsl_sec; file_counter++; } else { file_trksec[file_idx][0] = 0; file_trksec[file_idx][1] = 0; } } return file_counter; } // Load the info we need from floppy static void init_floppy_data(uint8_t *cur_trk, uint8_t *cur_file) { uint8_t initialized_correctly = 0; // Power on the drive and reset the head dii_power_on(DEFAULT_DRIVE_CONTROLLER_OFFSET, 0); dii_head_reposition(DEFAULT_DRIVE_CONTROLLER_OFFSET, 96, 0); // Head bang back to track 0! // Build a table that maps every file we're interested in to the track/sector of the first T/S list entry. initialized_correctly = fill_trksec_list(cur_trk) == FILE_LIST_LEN; // Load the first files to autoload for(uint8_t file_num = 0; file_num < AUTOLOAD_FILES && initialized_correctly; file_num++) { initialized_correctly = df_read_file(DEFAULT_DRIVE_CONTROLLER_OFFSET, file_trksec[file_num][0], file_trksec[file_num][1], (uint8_t*)file_load_address[file_num], cur_trk) && initialized_correctly; *cur_file = file_num; shared_page->next_module_idx = file_num; } // Power off dii_power_off(DEFAULT_DRIVE_CONTROLLER_OFFSET); // Check the CRC for the state page uint8_t crc = calculate_crc8((uint8_t*)file_load_address[STATE_FILE_IDX], sizeof(state_page_data) - 1); if(((state_page_data*)file_load_address[STATE_FILE_IDX])->crc != crc) { memset(((void*)file_load_address[STATE_FILE_IDX]), 0, sizeof(state_page_data)); } // If something went wrong, trigger a break if (!initialized_correctly) __asm volatile(" brk\n":::); } __task int main(void) { uint8_t cur_trk = 0; uint8_t cur_file = 0; uint8_t keep_going = 1; __disable_interrupts(); init(); init_floppy_data(&cur_trk, &cur_file); __enable_interrupts(); do { if((cur_file != shared_page->next_module_idx) || (shared_page->master_command == MASTER_COMMAND_SAVE)) { __disable_interrupts(); dii_power_on(DEFAULT_DRIVE_CONTROLLER_OFFSET, 0); // Check if we need to load another module if(cur_file != shared_page->next_module_idx) { cur_file = shared_page->next_module_idx; // Read the next module keep_going = df_read_file(DEFAULT_DRIVE_CONTROLLER_OFFSET, file_trksec[cur_file][0], file_trksec[cur_file][1], (uint8_t*)file_load_address[cur_file], &cur_trk); } // Check if we need to save the state page if (shared_page->master_command == MASTER_COMMAND_SAVE) { uint8_t crc = calculate_crc8((uint8_t*)file_load_address[STATE_FILE_IDX], sizeof(state_page_data) - 1); ((state_page_data*)file_load_address[STATE_FILE_IDX])->crc = crc; keep_going = keep_going && df_overwrite_file(DEFAULT_DRIVE_CONTROLLER_OFFSET, file_trksec[STATE_FILE_IDX][0], file_trksec[STATE_FILE_IDX][1], (uint8_t*)file_load_address[STATE_FILE_IDX], &cur_trk); } dii_power_off(DEFAULT_DRIVE_CONTROLLER_OFFSET); __enable_interrupts(); } shared_page->master_command = MASTER_COMMAND_NONE; // Execute the module (((void (*)(void))(MODULE_PAGE))()); } while(keep_going); __asm volatile(" brk\n":::); return 0; }