// Commander X16 Emulator // Copyright (c) 2019 Michael Steil // All rights reserved. License: 2-clause BSD #include #include #include "sdcard.h" #define SPI_CLOCK_RATE_MHZ 12.5f bool ss; bool busy; bool autotx; uint8_t sending_byte, received_byte; float outcounter; void vera_spi_init() { ss = false; busy = false; autotx = false; received_byte = 0xff; } void vera_spi_step(int mhz, int clocks) { if (busy) { outcounter += (float)clocks * SPI_CLOCK_RATE_MHZ / (float)mhz; if (outcounter >= 10) { // A value of 9 here is closer to reality, but hardware // can take slightly longer depending on clock-alignment. // 10 cycles here should be safe and won't succeed in emulation // while failing on hardware. busy = false; if (sdcard_attached) { received_byte = sdcard_handle(sending_byte); } else { received_byte = 0xff; } } } } uint8_t vera_spi_read(uint8_t reg) { switch (reg) { case 0: if (autotx && ss && !busy) { // autotx mode will automatically send $FF after each read sending_byte = 0xff; busy = true; outcounter = 0; } return received_byte; case 1: return busy << 7 | autotx << 2 | ss; } return 0; } void vera_spi_write(uint8_t reg, uint8_t value) { switch (reg) { case 0: if (ss && !busy) { sending_byte = value; busy = true; outcounter = 0; } break; case 1: if (ss != (value & 1)) { ss = value & 1; if (ss) { sdcard_select(ss); } } autotx = !!(value & 4); break; } }