Emulator for the Sharp CE-140F Diskette Driver

Dependencies:   mbed SDFileSystem

This is an attempt (for the time being, it isn't complete yet!) of emulating the Sharp CE-140F disk drive with a Nucleo board, attached to a Sharp Pocket Computer though its platform-proprietary 11-pin interface.

Committer:
ffxx68
Date:
Fri May 20 15:31:49 2022 +0000
Revision:
2:8b6005719a58
Parent:
1:cbecc06355fa
Child:
3:f829cb6eea98
Child:
4:6e0a5ddfcb82
changed approach - using interrupts

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ffxx68 0:832d44b89b24 1 #include "mbed.h"
ffxx68 0:832d44b89b24 2
ffxx68 2:8b6005719a58 3 #define BUF_SIZE 1024 // data depth
ffxx68 2:8b6005719a58 4 #define DEBUG_SIZE 1024 // print debug buffer
ffxx68 2:8b6005719a58 5 #define NIBBLE_DELAY_1 20 // us
ffxx68 2:8b6005719a58 6 #define NIBBLE_DELAY_2 20 // us
ffxx68 2:8b6005719a58 7 #define BIT_DELAY_1 100 // us
ffxx68 2:8b6005719a58 8 #define BIT_DELAY_2 2000 // us
ffxx68 2:8b6005719a58 9 #define ACK_DELAY 20000 // us
ffxx68 2:8b6005719a58 10 #define ACK_TIMEOUT 1 // s
ffxx68 2:8b6005719a58 11 #define DATA_WAIT 9000 // us
ffxx68 2:8b6005719a58 12 #define IN_DATAREADY_TIMEOUT 50000 // ms
ffxx68 0:832d44b89b24 13
ffxx68 2:8b6005719a58 14 // input ports
ffxx68 2:8b6005719a58 15 DigitalIn in_BUSY (D4);
ffxx68 2:8b6005719a58 16 InterruptIn irq_BUSY (D4);
ffxx68 2:8b6005719a58 17 DigitalIn in_D_OUT (D5);
ffxx68 2:8b6005719a58 18 InterruptIn irq_DOUT (D5);
ffxx68 2:8b6005719a58 19 DigitalIn in_X_OUT (D7);
ffxx68 2:8b6005719a58 20 InterruptIn irq_X_OUT (D7);
ffxx68 2:8b6005719a58 21 DigitalIn in_D_IN (D8);
ffxx68 2:8b6005719a58 22 DigitalIn in_SEL_2 (D10);
ffxx68 2:8b6005719a58 23 DigitalIn in_SEL_1 (D11);
ffxx68 2:8b6005719a58 24 // output ports
ffxx68 2:8b6005719a58 25 DigitalOut out_ACK (D9);
ffxx68 2:8b6005719a58 26 // info led
ffxx68 2:8b6005719a58 27 DigitalOut infoLed (LED1);
ffxx68 2:8b6005719a58 28 // timers
ffxx68 2:8b6005719a58 29 Timer mainTimer;
ffxx68 2:8b6005719a58 30 Timeout ackOffTimeout;
ffxx68 2:8b6005719a58 31 Timeout inDataReadyTimeout;
ffxx68 2:8b6005719a58 32 Ticker outDataTicker;
ffxx68 0:832d44b89b24 33
ffxx68 1:cbecc06355fa 34
ffxx68 2:8b6005719a58 35 // PC comms
ffxx68 2:8b6005719a58 36 RawSerial pc(USBTX, USBRX);
ffxx68 2:8b6005719a58 37 InterruptIn btn(USER_BUTTON);
ffxx68 2:8b6005719a58 38
ffxx68 2:8b6005719a58 39 volatile uint8_t deviceCode;
ffxx68 2:8b6005719a58 40 volatile uint8_t bitCount;
ffxx68 2:8b6005719a58 41 volatile char debugBuf[DEBUG_SIZE];
ffxx68 2:8b6005719a58 42 volatile char debugLine[80];
ffxx68 2:8b6005719a58 43 volatile bool highNibble = false;
ffxx68 2:8b6005719a58 44 volatile char inDataBuf[BUF_SIZE];
ffxx68 2:8b6005719a58 45 volatile char outDataBuf[BUF_SIZE];
ffxx68 2:8b6005719a58 46 volatile uint16_t inBufPosition;
ffxx68 2:8b6005719a58 47 volatile uint16_t outBufPosition;
ffxx68 2:8b6005719a58 48 volatile int checksum = 0;
ffxx68 0:832d44b89b24 49
ffxx68 2:8b6005719a58 50 void debug_log(const char *format, ...)
ffxx68 2:8b6005719a58 51 {
ffxx68 2:8b6005719a58 52 va_list args;
ffxx68 2:8b6005719a58 53 va_start(args, format);
ffxx68 2:8b6005719a58 54 sprintf((char*)debugLine,format,args);
ffxx68 2:8b6005719a58 55 sprintf((char*)debugLine,"%d %s\n\r",mainTimer.read_us(),(char*)debugLine);
ffxx68 2:8b6005719a58 56 strcat((char*)debugBuf,(char*)debugLine);
ffxx68 2:8b6005719a58 57 va_end(args);
ffxx68 2:8b6005719a58 58 }
ffxx68 2:8b6005719a58 59
ffxx68 2:8b6005719a58 60 // a "timeout" on ACK line
ffxx68 2:8b6005719a58 61 void ackOff ( void ) {
ffxx68 2:8b6005719a58 62
ffxx68 2:8b6005719a58 63 out_ACK = 0;
ffxx68 2:8b6005719a58 64 infoLed = 0;
ffxx68 2:8b6005719a58 65
ffxx68 2:8b6005719a58 66 }
ffxx68 0:832d44b89b24 67
ffxx68 2:8b6005719a58 68 char CheckSum(char b) {
ffxx68 2:8b6005719a58 69 checksum = (checksum + b) & 0xff;
ffxx68 2:8b6005719a58 70 return b;
ffxx68 2:8b6005719a58 71 }
ffxx68 2:8b6005719a58 72
ffxx68 2:8b6005719a58 73 void outDataAppend(char b) {
ffxx68 2:8b6005719a58 74 outDataBuf[(outBufPosition++)%BUF_SIZE ] = b;
ffxx68 2:8b6005719a58 75 }
ffxx68 2:8b6005719a58 76
ffxx68 2:8b6005719a58 77 void sendString(char* s) {
ffxx68 2:8b6005719a58 78 for (int i=0;i<strlen(s);i++){
ffxx68 2:8b6005719a58 79 outDataAppend(CheckSum(s[i]));
ffxx68 2:8b6005719a58 80 }
ffxx68 2:8b6005719a58 81 }
ffxx68 2:8b6005719a58 82
ffxx68 2:8b6005719a58 83 void inDataReady ( void ) {
ffxx68 2:8b6005719a58 84 // Command processing here ...
ffxx68 2:8b6005719a58 85 sprintf ( (char*)debugLine, "%d Processing...\n\r", mainTimer.read_us()) ; strcat ((char*)debugBuf, (char*)debugLine) ;
ffxx68 2:8b6005719a58 86 if ( inBufPosition > 0 ) {
ffxx68 2:8b6005719a58 87 sprintf ( (char*)debugLine, "%d inBufPosition %d...\n\r", mainTimer.read_us(), inBufPosition) ; strcat ((char*)debugBuf, (char*)debugLine) ;
ffxx68 0:832d44b89b24 88
ffxx68 2:8b6005719a58 89 // Verify checksum
ffxx68 2:8b6005719a58 90 checksum=0;
ffxx68 2:8b6005719a58 91 for (int i =0;i<inBufPosition;i++) {
ffxx68 2:8b6005719a58 92 checksum = (inDataBuf[i]+checksum) & 0xff;
ffxx68 2:8b6005719a58 93 }
ffxx68 2:8b6005719a58 94 debug_log ( "checksum %d vs %d" , checksum, inDataBuf[inBufPosition]);
ffxx68 2:8b6005719a58 95
ffxx68 2:8b6005719a58 96 // ....
ffxx68 2:8b6005719a58 97 debug_log ( "command 0x%02X" , inDataBuf[0]);
ffxx68 2:8b6005719a58 98 checksum=0;
ffxx68 2:8b6005719a58 99 outBufPosition = 0;
ffxx68 2:8b6005719a58 100
ffxx68 2:8b6005719a58 101 if ( inDataBuf[0] == 0x07 ) {
ffxx68 2:8b6005719a58 102 // case 0x07: process_FILES_LIST(1);break;
ffxx68 2:8b6005719a58 103 outDataAppend(0x00);
ffxx68 2:8b6005719a58 104 sendString("X:TEST .BAS ");
ffxx68 2:8b6005719a58 105 outDataAppend(checksum);
ffxx68 2:8b6005719a58 106 debug_log ( "dataout %d" , outBufPosition);
ffxx68 2:8b6005719a58 107 }
ffxx68 2:8b6005719a58 108 }
ffxx68 0:832d44b89b24 109 }
ffxx68 0:832d44b89b24 110
ffxx68 2:8b6005719a58 111 void nibbleReady ( void ) {
ffxx68 2:8b6005719a58 112
ffxx68 2:8b6005719a58 113 //pc.putc('n');
ffxx68 2:8b6005719a58 114 if ( out_ACK == 0 ) {
ffxx68 2:8b6005719a58 115 uint8_t dataByte;
ffxx68 2:8b6005719a58 116 wait_us ( NIBBLE_DELAY_1 );
ffxx68 2:8b6005719a58 117 if ( highNibble ) {
ffxx68 2:8b6005719a58 118 highNibble = false;
ffxx68 2:8b6005719a58 119 dataByte <<= 4;
ffxx68 2:8b6005719a58 120 dataByte |= in_SEL_1 + (in_SEL_2<<1) + (in_D_OUT<<2) + (in_D_IN<<3);
ffxx68 2:8b6005719a58 121 //pc.putc(dataByte);
ffxx68 2:8b6005719a58 122 inDataBuf [ (inBufPosition++)%BUF_SIZE ] = dataByte ; // circular storage for safety; may cut off data!
ffxx68 2:8b6005719a58 123 // Data processing starts after last byte (timeout reset at each byte received)
ffxx68 2:8b6005719a58 124 inDataReadyTimeout.attach( &inDataReady, IN_DATAREADY_TIMEOUT );
ffxx68 2:8b6005719a58 125 } else {
ffxx68 2:8b6005719a58 126 dataByte = in_SEL_1 + (in_SEL_1<<1) + (in_D_OUT<<2) + (in_D_IN<<3);
ffxx68 2:8b6005719a58 127 //pc.putc(dataByte);
ffxx68 2:8b6005719a58 128 highNibble = true;
ffxx68 2:8b6005719a58 129 }
ffxx68 2:8b6005719a58 130 sprintf ( (char*)debugLine, "%d nibble %d 0x%02X\n\r", mainTimer.read_us(), highNibble, dataByte ); strcat ( (char*)debugBuf, (char*)debugLine) ;
ffxx68 2:8b6005719a58 131 out_ACK = 1;
ffxx68 2:8b6005719a58 132 infoLed = 1;
ffxx68 2:8b6005719a58 133 ackOffTimeout.attach( &ackOff, ACK_TIMEOUT ); // max time high ack
ffxx68 2:8b6005719a58 134 } else {
ffxx68 2:8b6005719a58 135 out_ACK = 0;
ffxx68 2:8b6005719a58 136 }
ffxx68 2:8b6005719a58 137 }
ffxx68 0:832d44b89b24 138
ffxx68 2:8b6005719a58 139 void nibbleAck ( void ) {
ffxx68 2:8b6005719a58 140 if ( out_ACK == 1 ) {
ffxx68 2:8b6005719a58 141 wait_us ( NIBBLE_DELAY_2 );
ffxx68 2:8b6005719a58 142 out_ACK = 0;
ffxx68 2:8b6005719a58 143 infoLed = 0;
ffxx68 2:8b6005719a58 144 }
ffxx68 2:8b6005719a58 145 }
ffxx68 2:8b6005719a58 146
ffxx68 2:8b6005719a58 147
ffxx68 2:8b6005719a58 148 // Serial bit receive
ffxx68 2:8b6005719a58 149 void bitReady ( void ) {
ffxx68 2:8b6005719a58 150 uint32_t nTimeout;
ffxx68 0:832d44b89b24 151
ffxx68 2:8b6005719a58 152 //pc.putc('b');
ffxx68 2:8b6005719a58 153 if ( out_ACK == 1 ) {
ffxx68 2:8b6005719a58 154 bool bit;
ffxx68 2:8b6005719a58 155 wait_us ( BIT_DELAY_1 );
ffxx68 2:8b6005719a58 156
ffxx68 2:8b6005719a58 157 bit = in_D_OUT; // get bit value
ffxx68 2:8b6005719a58 158 //pc.putc(0x30+bit);pc.putc(' ');
ffxx68 2:8b6005719a58 159 sprintf ( (char*)debugLine, "%d bit %d: %d\n\r", mainTimer.read_us(), bitCount, bit ); strcat ( (char*)debugBuf, (char*)debugLine) ;
ffxx68 2:8b6005719a58 160 out_ACK = 0; // tell PC a bit has been received
ffxx68 2:8b6005719a58 161 infoLed = 0;
ffxx68 2:8b6005719a58 162
ffxx68 2:8b6005719a58 163 deviceCode>>=1;
ffxx68 2:8b6005719a58 164 if (bit) deviceCode|=0x80;
ffxx68 2:8b6005719a58 165 if ((bitCount=(++bitCount)&7)==0) {
ffxx68 2:8b6005719a58 166 // 8 bits received
ffxx68 2:8b6005719a58 167 irq_BUSY.rise(NULL); // detach this IRQ
ffxx68 2:8b6005719a58 168 pc.printf(" Device 0x%02X\n\r",deviceCode);
ffxx68 2:8b6005719a58 169 sprintf ( (char*)debugLine, "%d device 0x%02X\n\r", mainTimer.read_us(), deviceCode ); strcat ((char*)debugBuf, (char*)debugLine) ;
ffxx68 2:8b6005719a58 170 if ( deviceCode == 0x41 ) {
ffxx68 2:8b6005719a58 171 // PC is asking for a CE140F (device code SHOULD be 0x41) - Here we are!
ffxx68 2:8b6005719a58 172 sprintf ( (char*)debugLine, "%d CE140F\n\r", mainTimer.read_us()); strcat ((char*)debugBuf, (char*)debugLine) ;
ffxx68 2:8b6005719a58 173 // ... start data handling ...
ffxx68 2:8b6005719a58 174 highNibble = false;
ffxx68 2:8b6005719a58 175 // wait for both BUSY and X_OUT to go down, before starting data receive
ffxx68 2:8b6005719a58 176 nTimeout = 10000; // timeout: 1s
ffxx68 2:8b6005719a58 177 while ( ( in_X_OUT || in_BUSY ) && (nTimeout--) ) {
ffxx68 2:8b6005719a58 178 wait_us (100);
ffxx68 2:8b6005719a58 179 }
ffxx68 2:8b6005719a58 180 if (nTimeout) {
ffxx68 2:8b6005719a58 181 sprintf ( (char*)debugLine, "%d Data...\n\r", mainTimer.read_us()) ; strcat ((char*)debugBuf, (char*)debugLine) ;
ffxx68 2:8b6005719a58 182 out_ACK = 1;
ffxx68 2:8b6005719a58 183 infoLed = 1;
ffxx68 2:8b6005719a58 184 wait_us ( DATA_WAIT );
ffxx68 2:8b6005719a58 185 highNibble = false;
ffxx68 2:8b6005719a58 186 out_ACK = 0; // ready for receiving new data
ffxx68 2:8b6005719a58 187 infoLed = 0;
ffxx68 2:8b6005719a58 188 inBufPosition = 0;
ffxx68 2:8b6005719a58 189 irq_BUSY.rise(&nibbleReady);
ffxx68 2:8b6005719a58 190 irq_BUSY.fall(&nibbleAck);
ffxx68 2:8b6005719a58 191 } else {
ffxx68 2:8b6005719a58 192 pc.putc('x');
ffxx68 2:8b6005719a58 193 sprintf ( (char*)debugLine, "%d Timeout!\n\r", mainTimer.read_us()) ; strcat ((char*)debugBuf, (char*)debugLine) ;
ffxx68 2:8b6005719a58 194 }
ffxx68 2:8b6005719a58 195 }
ffxx68 2:8b6005719a58 196 } else {
ffxx68 2:8b6005719a58 197 wait_us ( BIT_DELAY_2 );
ffxx68 2:8b6005719a58 198 out_ACK = 1; // ready for a new bit
ffxx68 2:8b6005719a58 199 infoLed = 1;
ffxx68 2:8b6005719a58 200 ackOffTimeout.attach( &ackOff, ACK_TIMEOUT ); // max time high ack
ffxx68 2:8b6005719a58 201 }
ffxx68 0:832d44b89b24 202 }
ffxx68 0:832d44b89b24 203
ffxx68 0:832d44b89b24 204 }
ffxx68 0:832d44b89b24 205
ffxx68 0:832d44b89b24 206
ffxx68 0:832d44b89b24 207
ffxx68 2:8b6005719a58 208 void startDeviceCodeSeq ( void ) {
ffxx68 2:8b6005719a58 209
ffxx68 2:8b6005719a58 210 wait_us (BIT_DELAY_1);
ffxx68 2:8b6005719a58 211 if ( in_D_OUT == 1 ) {
ffxx68 2:8b6005719a58 212 // Device Code transfer starts with both X_OUT and DOUT high
ffxx68 2:8b6005719a58 213 // (X_OUT high with DOUT low is for cassette write)
ffxx68 2:8b6005719a58 214
ffxx68 2:8b6005719a58 215 infoLed = 1;
ffxx68 2:8b6005719a58 216 out_ACK = 1;
ffxx68 2:8b6005719a58 217 ackOffTimeout.attach( &ackOff, ACK_TIMEOUT ); // max time high ack
ffxx68 2:8b6005719a58 218
ffxx68 2:8b6005719a58 219 bitCount = 0;
ffxx68 2:8b6005719a58 220 deviceCode = 0;
ffxx68 2:8b6005719a58 221 sprintf ( (char*)debugBuf, "Device\n\r" );
ffxx68 0:832d44b89b24 222
ffxx68 2:8b6005719a58 223 wait_us (ACK_DELAY) ; //?? wait after eabling trigger?
ffxx68 2:8b6005719a58 224 // serial bit trigger
ffxx68 2:8b6005719a58 225 irq_BUSY.rise(&bitReady);
ffxx68 2:8b6005719a58 226 irq_BUSY.fall(NULL);
ffxx68 2:8b6005719a58 227 wait_us (ACK_DELAY) ;
ffxx68 2:8b6005719a58 228
ffxx68 0:832d44b89b24 229 }
ffxx68 0:832d44b89b24 230 }
ffxx68 0:832d44b89b24 231
ffxx68 0:832d44b89b24 232
ffxx68 2:8b6005719a58 233 void btnRaised()
ffxx68 2:8b6005719a58 234 {
ffxx68 2:8b6005719a58 235 uint8_t i = 20;
ffxx68 2:8b6005719a58 236 while (i--) { infoLed =! infoLed; wait_ms(20); }
ffxx68 2:8b6005719a58 237 // printout debug buffer
ffxx68 2:8b6005719a58 238 pc.printf ( "%s", (char*)debugBuf );
ffxx68 2:8b6005719a58 239 // reset status
ffxx68 2:8b6005719a58 240 out_ACK = 0;
ffxx68 2:8b6005719a58 241 infoLed = 0;
ffxx68 2:8b6005719a58 242 irq_BUSY.rise(NULL);
ffxx68 2:8b6005719a58 243 irq_BUSY.fall(NULL);
ffxx68 2:8b6005719a58 244 sprintf ( (char*)debugBuf, "Reset\n\r" );
ffxx68 2:8b6005719a58 245 }
ffxx68 2:8b6005719a58 246
ffxx68 2:8b6005719a58 247 int main(void) {
ffxx68 2:8b6005719a58 248 uint8_t i = 20;
ffxx68 2:8b6005719a58 249
ffxx68 2:8b6005719a58 250 pc.baud ( 57600 );
ffxx68 2:8b6005719a58 251 pc.printf ( "CE140F emulator init\n\r" );
ffxx68 2:8b6005719a58 252 while (i--) { infoLed =! infoLed; wait_ms(20); }
ffxx68 2:8b6005719a58 253
ffxx68 2:8b6005719a58 254 btn.rise(&btnRaised);
ffxx68 2:8b6005719a58 255 inBufPosition = 0;
ffxx68 2:8b6005719a58 256
ffxx68 2:8b6005719a58 257 // default input pull-down
ffxx68 2:8b6005719a58 258 in_BUSY.mode(PullNone);
ffxx68 2:8b6005719a58 259 in_D_OUT.mode(PullNone);
ffxx68 2:8b6005719a58 260 in_X_OUT.mode(PullNone);
ffxx68 2:8b6005719a58 261 in_D_IN.mode(PullNone);
ffxx68 2:8b6005719a58 262 in_SEL_2.mode(PullNone);
ffxx68 2:8b6005719a58 263 in_SEL_1.mode(PullNone);
ffxx68 2:8b6005719a58 264
ffxx68 2:8b6005719a58 265 // initial triggers
ffxx68 2:8b6005719a58 266 irq_X_OUT.rise(&startDeviceCodeSeq);
ffxx68 2:8b6005719a58 267
ffxx68 2:8b6005719a58 268 mainTimer.reset();
ffxx68 2:8b6005719a58 269 mainTimer.start();
ffxx68 2:8b6005719a58 270 //sprintf ( (char*)debugBuf, "Start\n\r" );
ffxx68 2:8b6005719a58 271
ffxx68 2:8b6005719a58 272 while (1) {
ffxx68 2:8b6005719a58 273 wait (1); // logic handled with interrupts and timers
ffxx68 2:8b6005719a58 274 }
ffxx68 2:8b6005719a58 275 }