USB Device Programming class project. This project allows a Python/Tk program running on a PC host to monitor/control a test-CPU programmed into an altera development board.
Dependencies: C12832_lcd USBDevice mbed-rtos mbed mmSPI
main.cpp@2:08655e2bb776, 2013-09-01 (annotated)
- Committer:
- gatedClock
- Date:
- Sun Sep 01 02:29:14 2013 +0000
- Revision:
- 2:08655e2bb776
- Parent:
- 0:9a314675a67d
- Child:
- 9:81726c95be74
add project code.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
gatedClock | 2:08655e2bb776 | 1 | /*----------------------------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 2 | student : m-moore |
gatedClock | 2:08655e2bb776 | 3 | email : gated.clock@gmail.com |
gatedClock | 2:08655e2bb776 | 4 | class : usb device drivers |
gatedClock | 2:08655e2bb776 | 5 | directory : USB_device_project |
gatedClock | 2:08655e2bb776 | 6 | file : main.cpp |
gatedClock | 2:08655e2bb776 | 7 | date : september 3, 2013. |
gatedClock | 2:08655e2bb776 | 8 | ----copyright-----------------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 9 | licensed for personal and academic use. |
gatedClock | 2:08655e2bb776 | 10 | commercial use must be approved by the account-holder of |
gatedClock | 2:08655e2bb776 | 11 | gated.clock@gmail.com |
gatedClock | 2:08655e2bb776 | 12 | ----description---------------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 13 | overview: |
gatedClock | 2:08655e2bb776 | 14 | program to provide round-trip communication between a python test-control |
gatedClock | 2:08655e2bb776 | 15 | program running on a pc host, and a device-under-test CPU implemented on |
gatedClock | 2:08655e2bb776 | 16 | an altera board. the pc-host communication is over USBSerial, and the |
gatedClock | 2:08655e2bb776 | 17 | altera communication is over SPI. |
gatedClock | 2:08655e2bb776 | 18 | |
gatedClock | 2:08655e2bb776 | 19 | features: |
gatedClock | 2:08655e2bb776 | 20 | 1. multi-threaded design, use of memory-pools to transfer data between threads. |
gatedClock | 2:08655e2bb776 | 21 | 2. use of USBDevice library for communication with PC host. |
gatedClock | 2:08655e2bb776 | 22 | 3. use of mmSPI custom library for communication with FPGA. |
gatedClock | 2:08655e2bb776 | 23 | 4. main thread provides USBSerial communication to/from host. |
gatedClock | 2:08655e2bb776 | 24 | 5. SPI processing thread provides SPI communication to/from DUT. |
gatedClock | 2:08655e2bb776 | 25 | 6. mmSPI library generates non-overlapping SPI and CPU clocks. |
gatedClock | 2:08655e2bb776 | 26 | 7. background diagnostic thread provides LCD & LED updates. |
gatedClock | 0:9a314675a67d | 27 | |
gatedClock | 2:08655e2bb776 | 28 | indicators: (led<3:0> = LED<1:4>) |
gatedClock | 2:08655e2bb776 | 29 | 1. LCD provides running counts for SPI and CPU clock cycles. |
gatedClock | 2:08655e2bb776 | 30 | 2. led0 indicates main thread processing. |
gatedClock | 2:08655e2bb776 | 31 | 3. led1 indicates SPI thread processing. |
gatedClock | 2:08655e2bb776 | 32 | 4. led2 indicates LCD thread processing. |
gatedClock | 2:08655e2bb776 | 33 | 5. led3 indicates reply-to-host underflow (should never turn on). |
gatedClock | 2:08655e2bb776 | 34 | |
gatedClock | 2:08655e2bb776 | 35 | implementation: |
gatedClock | 2:08655e2bb776 | 36 | 1. main.processIncomingSerial(): accept incoming serial data from host, |
gatedClock | 2:08655e2bb776 | 37 | and map it into tFromHost structures. |
gatedClock | 2:08655e2bb776 | 38 | 2. SPIprocessingThread: take the incoming data structures instances, and |
gatedClock | 2:08655e2bb776 | 39 | feed their content into mmSPI commands. |
gatedClock | 2:08655e2bb776 | 40 | 3. mmSPI object: given commands/data passed from caller, |
gatedClock | 2:08655e2bb776 | 41 | map them into SPI outgoing vectors and scan them into the FPGA. |
gatedClock | 2:08655e2bb776 | 42 | 4. mmSPI object: receive incoming SPI vectors from FPGA. |
gatedClock | 2:08655e2bb776 | 43 | make FPGA payload data available to caller. |
gatedClock | 2:08655e2bb776 | 44 | 5. SPIprocessingThread: load tToHost structures with said FPGA payload data. |
gatedClock | 2:08655e2bb776 | 45 | 6. main.processOutgoingSerial(): transfer tToHost structure data into a |
gatedClock | 2:08655e2bb776 | 46 | serial outgoing buffer, and block-transfer it to the host PC. |
gatedClock | 2:08655e2bb776 | 47 | |
gatedClock | 2:08655e2bb776 | 48 | electrical: |
gatedClock | 2:08655e2bb776 | 49 | 1. four pins (and ground) attached to the zigbee header, |
gatedClock | 2:08655e2bb776 | 50 | programmed as three SPI pins and the CPU clock. |
gatedClock | 2:08655e2bb776 | 51 | 2. each of the four signals over twisted-pair. |
gatedClock | 2:08655e2bb776 | 52 | 3. but some ribbon cable is used at the FPGA end. |
gatedClock | 2:08655e2bb776 | 53 | 4. best if only the mbed application board USB cable is attached |
gatedClock | 2:08655e2bb776 | 54 | to the host; if the mbed CPU board USB cable is also attached to |
gatedClock | 2:08655e2bb776 | 55 | the host, then the python program may attempt to use the wrong USB |
gatedClock | 2:08655e2bb776 | 56 | connection. |
gatedClock | 2:08655e2bb776 | 57 | 5. no particular power sequence is needed for this system to work. |
gatedClock | 2:08655e2bb776 | 58 | |
gatedClock | 2:08655e2bb776 | 59 | |
gatedClock | 2:08655e2bb776 | 60 | testing: |
gatedClock | 2:08655e2bb776 | 61 | the python UI provides the main testing mechanism. |
gatedClock | 2:08655e2bb776 | 62 | |
gatedClock | 2:08655e2bb776 | 63 | USB connect. |
gatedClock | 2:08655e2bb776 | 64 | 00. press 'CONNECT' button in UI. verify connection info in shell. |
gatedClock | 2:08655e2bb776 | 65 | |
gatedClock | 2:08655e2bb776 | 66 | CPU register w/r |
gatedClock | 2:08655e2bb776 | 67 | 01. type values into {R0,R1,R2,R3,PC,IR} UI entry-forms. |
gatedClock | 2:08655e2bb776 | 68 | 02. press 'REG WRITE' UI button. |
gatedClock | 2:08655e2bb776 | 69 | 03. press 'REG READ' UI button. |
gatedClock | 2:08655e2bb776 | 70 | 04. verify that the read data is correct. |
gatedClock | 2:08655e2bb776 | 71 | |
gatedClock | 2:08655e2bb776 | 72 | CPU main-memory w/r |
gatedClock | 2:08655e2bb776 | 73 | 05. type an address into 'mmADR' UI entry-form. |
gatedClock | 2:08655e2bb776 | 74 | 06. type data into 'mmVAL' UI entry-form. |
gatedClock | 2:08655e2bb776 | 75 | 07. press 'MM WRITE' UI button. |
gatedClock | 2:08655e2bb776 | 76 | 08. type a different address into 'mmADR' UI entry-form. |
gatedClock | 2:08655e2bb776 | 77 | 09. type different data into 'mmVAL' UI entry-form. |
gatedClock | 2:08655e2bb776 | 78 | 10. press 'MM WRITE' UI button. |
gatedClock | 2:08655e2bb776 | 79 | 11. type address from (05) into 'mmADR' UI entry-form. |
gatedClock | 2:08655e2bb776 | 80 | 12. press 'MM READ' UI button. |
gatedClock | 2:08655e2bb776 | 81 | 13. verify that the data from (06) is seen in the 'mmVAL' entry form. |
gatedClock | 2:08655e2bb776 | 82 | 14. type address from (08) into 'mmADR' UI entry-form. |
gatedClock | 2:08655e2bb776 | 83 | 15. press 'MM READ' UI button. |
gatedClock | 2:08655e2bb776 | 84 | 16. verify that the data from (09) is seen in the 'mmVAL' entry form. |
gatedClock | 2:08655e2bb776 | 85 | |
gatedClock | 2:08655e2bb776 | 86 | CPU main-memory full load/dump. |
gatedClock | 2:08655e2bb776 | 87 | 17. press 'PROGRAM' in the UI. select a program file in the dialog-popup. |
gatedClock | 2:08655e2bb776 | 88 | 18. watch the load process in the shell text. |
gatedClock | 2:08655e2bb776 | 89 | 19. press 'DUMP in the UI. select a main-memory dump file in the diaglog-popup. |
gatedClock | 2:08655e2bb776 | 90 | 20. watch the dump process in the shell text. |
gatedClock | 2:08655e2bb776 | 91 | |
gatedClock | 2:08655e2bb776 | 92 | CPU step function. |
gatedClock | 2:08655e2bb776 | 93 | 21. press 'STEP' in the UI repeatedly, watch the UI display the |
gatedClock | 2:08655e2bb776 | 94 | CPU register states as the current program is executed one CPU clock |
gatedClock | 2:08655e2bb776 | 95 | at a time. |
gatedClock | 2:08655e2bb776 | 96 | |
gatedClock | 2:08655e2bb776 | 97 | CPU run function. |
gatedClock | 2:08655e2bb776 | 98 | 22. press 'RUN' in the UI. watch the current program run at high speed. |
gatedClock | 2:08655e2bb776 | 99 | 23. press 'SLOW' in the UI. watch the current program run at slow speed. |
gatedClock | 2:08655e2bb776 | 100 | 24. press 'STOP' in the UI. the program will stop execution. |
gatedClock | 2:08655e2bb776 | 101 | |
gatedClock | 2:08655e2bb776 | 102 | CPU test function. |
gatedClock | 2:08655e2bb776 | 103 | 25. press 'TEST' in the UI. the program will load,execute,dump,compare. |
gatedClock | 2:08655e2bb776 | 104 | 26. tail -f testlog.txt to see test status. |
gatedClock | 2:08655e2bb776 | 105 | 27. the test will repeat until 'STOP TEST' is pressed. |
gatedClock | 2:08655e2bb776 | 106 | 28. long test performed by allowing this mode to continue. |
gatedClock | 2:08655e2bb776 | 107 | |
gatedClock | 2:08655e2bb776 | 108 | UI exit function. |
gatedClock | 2:08655e2bb776 | 109 | 29. press 'EXIT' in the UI. it will exit. |
gatedClock | 2:08655e2bb776 | 110 | -----includes-----------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 111 | #include "mbed.h" // general. |
gatedClock | 2:08655e2bb776 | 112 | #include "USBSerial.h" // serial over USB. |
gatedClock | 2:08655e2bb776 | 113 | #include "C12832_lcd.h" // LCD display. |
gatedClock | 2:08655e2bb776 | 114 | #include "rtos.h" // RTOS. |
gatedClock | 2:08655e2bb776 | 115 | #include "mmSPI.h" // SPI. |
gatedClock | 2:08655e2bb776 | 116 | //---defines------------------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 117 | #define LCD1 lcd.locate(0, 0); // LCD line 1. |
gatedClock | 2:08655e2bb776 | 118 | #define LCD2 lcd.locate(0,11); // LCD line 2. |
gatedClock | 2:08655e2bb776 | 119 | #define LCD3 lcd.locate(0,22); // LCD line 3. |
gatedClock | 2:08655e2bb776 | 120 | #define LCD3 lcd.locate(0,22); // LCD line 3. |
gatedClock | 2:08655e2bb776 | 121 | #define SPI_BYTES 8 // number of SPI bytes. |
gatedClock | 2:08655e2bb776 | 122 | #define SPI_HZ 100000 // SPI frequency in Hz. |
gatedClock | 2:08655e2bb776 | 123 | #define SER_BYTES 8 // serial in/out # of bytes. |
gatedClock | 2:08655e2bb776 | 124 | #define SER_ALIGN 7 // '$' location in shift-register. |
gatedClock | 2:08655e2bb776 | 125 | #define THREAD_0_WAIT 8 // multitasking wait mS. |
gatedClock | 2:08655e2bb776 | 126 | #define THREAD_1_WAIT 2 // multitasking wait mS. |
gatedClock | 2:08655e2bb776 | 127 | #define THREAD_2_WAIT 128 // multitasking wait mS. |
gatedClock | 2:08655e2bb776 | 128 | #define HB_MODULO 64 // heartbeat slowdown factor. |
gatedClock | 2:08655e2bb776 | 129 | #define POOL_LEN 16 // memory pool dimension. |
gatedClock | 2:08655e2bb776 | 130 | #define HCMD_SETREG 1 // host command 'set register'. |
gatedClock | 2:08655e2bb776 | 131 | #define HCMD_GETREG 2 // host command 'get register'. |
gatedClock | 2:08655e2bb776 | 132 | #define HCMD_SETMM 3 // host command 'set main-memory.' |
gatedClock | 2:08655e2bb776 | 133 | #define HCMD_GETMM 4 // host command 'get main-memory.' |
gatedClock | 2:08655e2bb776 | 134 | #define HCMD_STEP 5 // host command 'step-CPU'. |
gatedClock | 2:08655e2bb776 | 135 | #define HCMD_SETIR 6 // host command 'set-IR'. |
gatedClock | 2:08655e2bb776 | 136 | #define CPU_REG_0 0 // CPU register 0. |
gatedClock | 2:08655e2bb776 | 137 | #define CPU_REG_1 1 // CPU register 1. |
gatedClock | 2:08655e2bb776 | 138 | #define CPU_REG_2 2 // CPU register 2. |
gatedClock | 2:08655e2bb776 | 139 | #define CPU_REG_3 3 // CPU register 3. |
gatedClock | 2:08655e2bb776 | 140 | #define CPU_REG_PC 4 // CPU Program Counter. |
gatedClock | 2:08655e2bb776 | 141 | #define CPU_IR_H 5 // CPU IR high-byte. |
gatedClock | 2:08655e2bb776 | 142 | #define CPU_IR_L 6 // CPU IR low-byte. |
gatedClock | 2:08655e2bb776 | 143 | //--global_definitions--------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 144 | struct tFromHost // command from host. |
gatedClock | 2:08655e2bb776 | 145 | { |
gatedClock | 2:08655e2bb776 | 146 | char cCommand; // command from host. |
gatedClock | 2:08655e2bb776 | 147 | char cRegisterID; // which CPU register. |
gatedClock | 2:08655e2bb776 | 148 | char cRegisterValue; // write this to CPU register. |
gatedClock | 2:08655e2bb776 | 149 | char cIRValueH; // write this to IR. |
gatedClock | 2:08655e2bb776 | 150 | char cIRValueL; // write this to IR. |
gatedClock | 2:08655e2bb776 | 151 | char cMMaddress; // access this MM address. |
gatedClock | 2:08655e2bb776 | 152 | char cMMdataH; // MM content high byte. |
gatedClock | 2:08655e2bb776 | 153 | char cMMdataL; // MM content low byte. |
gatedClock | 2:08655e2bb776 | 154 | }; |
gatedClock | 2:08655e2bb776 | 155 | MemoryPool<tFromHost, POOL_LEN> mPoolFromHost; |
gatedClock | 2:08655e2bb776 | 156 | Queue <tFromHost, POOL_LEN> qFromHost; |
gatedClock | 2:08655e2bb776 | 157 | |
gatedClock | 2:08655e2bb776 | 158 | //---- |
gatedClock | 2:08655e2bb776 | 159 | |
gatedClock | 2:08655e2bb776 | 160 | struct tToHost // reply to host. |
gatedClock | 2:08655e2bb776 | 161 | { |
gatedClock | 2:08655e2bb776 | 162 | char cCommand; // command executed. |
gatedClock | 2:08655e2bb776 | 163 | char cRegisterID; // which CPU register read. |
gatedClock | 2:08655e2bb776 | 164 | char cRegisterValue; // data from CPU register. |
gatedClock | 2:08655e2bb776 | 165 | char cMMaddress; // which MM address read. |
gatedClock | 2:08655e2bb776 | 166 | char cMMdataH; // MM content high byte. |
gatedClock | 2:08655e2bb776 | 167 | char cMMdataL; // MM content low byte. |
gatedClock | 2:08655e2bb776 | 168 | }; |
gatedClock | 2:08655e2bb776 | 169 | MemoryPool<tToHost, POOL_LEN> mPoolToHost; |
gatedClock | 2:08655e2bb776 | 170 | Queue <tToHost, POOL_LEN> qToHost; |
gatedClock | 2:08655e2bb776 | 171 | //--global_variables----------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 172 | char gpcSerialFromHost[SER_BYTES]; // incoming serial buffer. |
gatedClock | 2:08655e2bb776 | 173 | char gpcSerialToHost [SER_BYTES]; // outgoing serial buffer. |
gatedClock | 2:08655e2bb776 | 174 | char gcNewCommand; // new command from host. |
gatedClock | 2:08655e2bb776 | 175 | int gdRoundTrip; // +1 from host, -1 to host. |
gatedClock | 2:08655e2bb776 | 176 | tToHost * gpToHost; // to-host structure. |
gatedClock | 2:08655e2bb776 | 177 | osEvent gqToHostEvent; // incoming message event. |
gatedClock | 2:08655e2bb776 | 178 | unsigned long gulSPIclkCount; // SPI clock count. |
gatedClock | 2:08655e2bb776 | 179 | unsigned long gulCPUclkCount; // CPU clock count. |
gatedClock | 2:08655e2bb776 | 180 | //--global_instances----------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 181 | USBSerial serial; // serial over usb. |
gatedClock | 2:08655e2bb776 | 182 | C12832_LCD lcd; // LCD display. |
gatedClock | 2:08655e2bb776 | 183 | DigitalOut led0(LED4); // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 184 | DigitalOut led1(LED3); // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 185 | DigitalOut led2(LED2); // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 186 | DigitalOut led3(LED1); // SPI reply underflow warning. |
gatedClock | 2:08655e2bb776 | 187 | //-------prototypes-----------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 188 | int main(); // main. |
gatedClock | 2:08655e2bb776 | 189 | void processIncomingSerial(); // process incoming host data. |
gatedClock | 2:08655e2bb776 | 190 | void processOutgoingSerial(); // process outgoing data to host. |
gatedClock | 2:08655e2bb776 | 191 | void SPIprocessingThread(void const *args); // SPI-side processing. |
gatedClock | 2:08655e2bb776 | 192 | void diagnosticThread (void const *args); // LCD and LED notifications. |
gatedClock | 2:08655e2bb776 | 193 | char ascii_nibble_to_binary(char cAscii); // ascii nibble -> binary. |
gatedClock | 2:08655e2bb776 | 194 | char binary_to_ascii_nibble(char cBinary); // binary -> ascii nibble. |
gatedClock | 2:08655e2bb776 | 195 | void clear_tFromHost(tFromHost *ptFromHost);// initialize structure. |
gatedClock | 2:08655e2bb776 | 196 | void clear_tToHost (tToHost *ptToHost); // initialize structure. |
gatedClock | 2:08655e2bb776 | 197 | //==============================================//============================== |
gatedClock | 2:08655e2bb776 | 198 | int main(void) // USBSerial processing thread. |
gatedClock | 2:08655e2bb776 | 199 | { |
gatedClock | 2:08655e2bb776 | 200 | int dHeartbeat; // heartbeat counter. |
gatedClock | 2:08655e2bb776 | 201 | int dLoop; // loop index. |
gatedClock | 2:08655e2bb776 | 202 | |
gatedClock | 2:08655e2bb776 | 203 | gpToHost = NULL; // initialize global. |
gatedClock | 2:08655e2bb776 | 204 | gcNewCommand = 0; // initialize global. |
gatedClock | 2:08655e2bb776 | 205 | gdRoundTrip = 1024; // initialize global. |
gatedClock | 2:08655e2bb776 | 206 | gulSPIclkCount = 0; // initialize global. |
gatedClock | 2:08655e2bb776 | 207 | gulCPUclkCount = 0; // initialize global. |
gatedClock | 2:08655e2bb776 | 208 | dHeartbeat = 0; // initialize local. |
gatedClock | 2:08655e2bb776 | 209 | dLoop = 0; // initialize local. |
gatedClock | 2:08655e2bb776 | 210 | |
gatedClock | 2:08655e2bb776 | 211 | // initialize serial-in shift-register. |
gatedClock | 2:08655e2bb776 | 212 | for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialFromHost[dLoop] = 0; |
gatedClock | 2:08655e2bb776 | 213 | |
gatedClock | 2:08655e2bb776 | 214 | // thread-out SPI-side processing. |
gatedClock | 2:08655e2bb776 | 215 | Thread thread_1(SPIprocessingThread,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL); |
gatedClock | 2:08655e2bb776 | 216 | |
gatedClock | 2:08655e2bb776 | 217 | // thread-out diagnostics. |
gatedClock | 2:08655e2bb776 | 218 | Thread thread_2(diagnosticThread,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); |
gatedClock | 2:08655e2bb776 | 219 | |
gatedClock | 2:08655e2bb776 | 220 | while(1) // main loop. |
gatedClock | 2:08655e2bb776 | 221 | { |
gatedClock | 2:08655e2bb776 | 222 | processIncomingSerial(); // process data in from host. |
gatedClock | 2:08655e2bb776 | 223 | processOutgoingSerial(); // process data out to host. |
gatedClock | 2:08655e2bb776 | 224 | |
gatedClock | 2:08655e2bb776 | 225 | dHeartbeat++; // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 226 | if (!(dHeartbeat % HB_MODULO)) led0 = !led0; |
gatedClock | 2:08655e2bb776 | 227 | Thread::wait(THREAD_0_WAIT); // multitasking. |
gatedClock | 2:08655e2bb776 | 228 | } // main loop. |
gatedClock | 2:08655e2bb776 | 229 | } // main. |
gatedClock | 2:08655e2bb776 | 230 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 231 | /* |
gatedClock | 2:08655e2bb776 | 232 | the python program running on the host is sending/receiving ascii characters |
gatedClock | 2:08655e2bb776 | 233 | which represent command/data binary nibbles. the python program will send |
gatedClock | 2:08655e2bb776 | 234 | the '$' character for command-string alignment. this function reads-in the |
gatedClock | 2:08655e2bb776 | 235 | incoming serial stream when any serial data is available, into a shift-register, |
gatedClock | 2:08655e2bb776 | 236 | and breaks upon detection of the '$' alignment character for python |
gatedClock | 2:08655e2bb776 | 237 | command-processing. at that point the shift-register will look something like |
gatedClock | 2:08655e2bb776 | 238 | [0] [1] [2] [3] [4] [5] [6] [7] |
gatedClock | 2:08655e2bb776 | 239 | '1' '2' '3' '4' x x x '$' (means write 0x34 to CPU R2). |
gatedClock | 2:08655e2bb776 | 240 | |
gatedClock | 2:08655e2bb776 | 241 | |
gatedClock | 2:08655e2bb776 | 242 | command-host register-number interpretation: |
gatedClock | 2:08655e2bb776 | 243 | 0 = CPU R0. |
gatedClock | 2:08655e2bb776 | 244 | 1 = CPU R1. |
gatedClock | 2:08655e2bb776 | 245 | 2 = CPU R2. |
gatedClock | 2:08655e2bb776 | 246 | 3 = CPU R3. |
gatedClock | 2:08655e2bb776 | 247 | 4 = CPU program-counter. |
gatedClock | 2:08655e2bb776 | 248 | 5 = CPU instruction-register high-byte. |
gatedClock | 2:08655e2bb776 | 249 | 6 = CPU instruction-register low-byte. |
gatedClock | 2:08655e2bb776 | 250 | |
gatedClock | 2:08655e2bb776 | 251 | instruction-register write is specially implemented, |
gatedClock | 2:08655e2bb776 | 252 | instruction-register read is implemented as two standard register-reads. |
gatedClock | 2:08655e2bb776 | 253 | |
gatedClock | 2:08655e2bb776 | 254 | host-command shift-register interpretation: |
gatedClock | 2:08655e2bb776 | 255 | |
gatedClock | 2:08655e2bb776 | 256 | gpcSerialFromHost[0] = command. |
gatedClock | 2:08655e2bb776 | 257 | subsequent interpretation depends on the command. |
gatedClock | 2:08655e2bb776 | 258 | |
gatedClock | 2:08655e2bb776 | 259 | ---- |
gatedClock | 2:08655e2bb776 | 260 | if command = HCMD_SETREG (write-CPU-register) or HCMD_GETREG (read-CPU-register): |
gatedClock | 2:08655e2bb776 | 261 | |
gatedClock | 2:08655e2bb776 | 262 | gpcSerialFromHost[1] = register number (see above). |
gatedClock | 2:08655e2bb776 | 263 | gpcSerialFromHost[2] = register content, high nibble. |
gatedClock | 2:08655e2bb776 | 264 | gpcSerialFromHost[3] = register content, low nibble. |
gatedClock | 2:08655e2bb776 | 265 | gpcSerialFromHost[4] = not used. |
gatedClock | 2:08655e2bb776 | 266 | gpcSerialFromHost[5] = not used. |
gatedClock | 2:08655e2bb776 | 267 | gpcSerialFromHost[6] = not used. |
gatedClock | 2:08655e2bb776 | 268 | |
gatedClock | 2:08655e2bb776 | 269 | ---- |
gatedClock | 2:08655e2bb776 | 270 | if command = HCMD_SETIR (write-CPU-instruction-register): |
gatedClock | 2:08655e2bb776 | 271 | |
gatedClock | 2:08655e2bb776 | 272 | gpcSerialFromHost[1] = IR register number, implied anyway. |
gatedClock | 2:08655e2bb776 | 273 | gpcSerialFromHost[2] = IR write value high byte high nibble. |
gatedClock | 2:08655e2bb776 | 274 | gpcSerialFromHost[3] = IR write value high byte low nibble. |
gatedClock | 2:08655e2bb776 | 275 | gpcSerialFromHost[4] = IR write value low byte high nibble. |
gatedClock | 2:08655e2bb776 | 276 | gpcSerialFromHost[5] = IR write value low byte low nibble. |
gatedClock | 2:08655e2bb776 | 277 | gpcSerialFromHost[6] = not used. |
gatedClock | 2:08655e2bb776 | 278 | |
gatedClock | 2:08655e2bb776 | 279 | ---- |
gatedClock | 2:08655e2bb776 | 280 | if command = HCMD_SETMM (write to CPU main-memory) or HCMD_GETMM (read from CPU main-memory): |
gatedClock | 2:08655e2bb776 | 281 | |
gatedClock | 2:08655e2bb776 | 282 | gpcSerialFromHost[1] = MM address high nibble. |
gatedClock | 2:08655e2bb776 | 283 | gpcSerialFromHost[2] = MM address low nibble. |
gatedClock | 2:08655e2bb776 | 284 | gpcSerialFromHost[3] = MM content high byte high nibble. |
gatedClock | 2:08655e2bb776 | 285 | gpcSerialFromHost[4] = MM content high byte low nibble. |
gatedClock | 2:08655e2bb776 | 286 | gpcSerialFromHost[5] = MM content low byte high nibble. |
gatedClock | 2:08655e2bb776 | 287 | gpcSerialFromHost[6] = MM content low byte low nibble. |
gatedClock | 2:08655e2bb776 | 288 | |
gatedClock | 2:08655e2bb776 | 289 | the above also applies to function 'processOutgoingSerial'. |
gatedClock | 2:08655e2bb776 | 290 | */ |
gatedClock | 0:9a314675a67d | 291 | |
gatedClock | 2:08655e2bb776 | 292 | void processIncomingSerial(void) // process incoming serial data. |
gatedClock | 2:08655e2bb776 | 293 | { |
gatedClock | 2:08655e2bb776 | 294 | int dLoop; // loop index. |
gatedClock | 2:08655e2bb776 | 295 | tFromHost * pFromHost; // from-host structure. |
gatedClock | 2:08655e2bb776 | 296 | |
gatedClock | 2:08655e2bb776 | 297 | while(serial.available()) // while data from host is available. |
gatedClock | 2:08655e2bb776 | 298 | { |
gatedClock | 2:08655e2bb776 | 299 | // shift-in the serial stream. |
gatedClock | 2:08655e2bb776 | 300 | for (dLoop = 0; dLoop < (SER_BYTES - 1); dLoop++) |
gatedClock | 2:08655e2bb776 | 301 | gpcSerialFromHost[dLoop] = gpcSerialFromHost[dLoop + 1]; |
gatedClock | 2:08655e2bb776 | 302 | gpcSerialFromHost[SER_BYTES - 1] = serial._getc(); |
gatedClock | 2:08655e2bb776 | 303 | |
gatedClock | 2:08655e2bb776 | 304 | if (gpcSerialFromHost[SER_ALIGN] == '$')// data from host is aligned. |
gatedClock | 2:08655e2bb776 | 305 | { |
gatedClock | 2:08655e2bb776 | 306 | gcNewCommand = 1; // new host command just recognised. |
gatedClock | 2:08655e2bb776 | 307 | break; // need to process aligned data. |
gatedClock | 2:08655e2bb776 | 308 | } // data from host is aligned. |
gatedClock | 2:08655e2bb776 | 309 | } // while data from host is available. |
gatedClock | 2:08655e2bb776 | 310 | |
gatedClock | 2:08655e2bb776 | 311 | // even if more data awaits from the |
gatedClock | 2:08655e2bb776 | 312 | // incoming serial stream, we now need |
gatedClock | 2:08655e2bb776 | 313 | // to process the aligned data recognised |
gatedClock | 2:08655e2bb776 | 314 | // as a command from the host. |
gatedClock | 2:08655e2bb776 | 315 | |
gatedClock | 2:08655e2bb776 | 316 | if (gcNewCommand) // execute once per new command. |
gatedClock | 2:08655e2bb776 | 317 | { |
gatedClock | 2:08655e2bb776 | 318 | pFromHost = mPoolFromHost.alloc(); // allocate next pool entry. |
gatedClock | 2:08655e2bb776 | 319 | if (!pFromHost) error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); |
gatedClock | 2:08655e2bb776 | 320 | clear_tFromHost(pFromHost); // initialize structure. |
gatedClock | 2:08655e2bb776 | 321 | |
gatedClock | 2:08655e2bb776 | 322 | // copy-in host message. |
gatedClock | 2:08655e2bb776 | 323 | pFromHost->cCommand = ascii_nibble_to_binary(gpcSerialFromHost[0]); |
gatedClock | 2:08655e2bb776 | 324 | |
gatedClock | 2:08655e2bb776 | 325 | // host requests register access. |
gatedClock | 2:08655e2bb776 | 326 | if (pFromHost->cCommand == HCMD_SETREG || pFromHost->cCommand == HCMD_GETREG) |
gatedClock | 2:08655e2bb776 | 327 | { |
gatedClock | 2:08655e2bb776 | 328 | pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); |
gatedClock | 2:08655e2bb776 | 329 | pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + |
gatedClock | 2:08655e2bb776 | 330 | ascii_nibble_to_binary(gpcSerialFromHost[3]); |
gatedClock | 2:08655e2bb776 | 331 | } |
gatedClock | 2:08655e2bb776 | 332 | |
gatedClock | 2:08655e2bb776 | 333 | |
gatedClock | 2:08655e2bb776 | 334 | if (pFromHost->cCommand == HCMD_SETIR) // host requests IR write. |
gatedClock | 2:08655e2bb776 | 335 | { |
gatedClock | 2:08655e2bb776 | 336 | pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + |
gatedClock | 2:08655e2bb776 | 337 | ascii_nibble_to_binary(gpcSerialFromHost[3]); |
gatedClock | 2:08655e2bb776 | 338 | pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + |
gatedClock | 2:08655e2bb776 | 339 | ascii_nibble_to_binary(gpcSerialFromHost[5]); |
gatedClock | 2:08655e2bb776 | 340 | } |
gatedClock | 2:08655e2bb776 | 341 | |
gatedClock | 2:08655e2bb776 | 342 | |
gatedClock | 2:08655e2bb776 | 343 | // host requests main-memory access. |
gatedClock | 2:08655e2bb776 | 344 | if (pFromHost->cCommand == HCMD_SETMM || pFromHost->cCommand == HCMD_GETMM) |
gatedClock | 2:08655e2bb776 | 345 | { |
gatedClock | 2:08655e2bb776 | 346 | pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + |
gatedClock | 2:08655e2bb776 | 347 | ascii_nibble_to_binary(gpcSerialFromHost[2]); |
gatedClock | 2:08655e2bb776 | 348 | pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + |
gatedClock | 2:08655e2bb776 | 349 | ascii_nibble_to_binary(gpcSerialFromHost[4]); |
gatedClock | 2:08655e2bb776 | 350 | pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + |
gatedClock | 2:08655e2bb776 | 351 | ascii_nibble_to_binary(gpcSerialFromHost[6]); |
gatedClock | 2:08655e2bb776 | 352 | } // host requests main-memory access. |
gatedClock | 2:08655e2bb776 | 353 | |
gatedClock | 2:08655e2bb776 | 354 | if (pFromHost->cCommand == HCMD_GETREG || pFromHost->cCommand == HCMD_GETMM) |
gatedClock | 2:08655e2bb776 | 355 | gdRoundTrip++; // expected reply to host is pending. |
gatedClock | 2:08655e2bb776 | 356 | qFromHost.put(pFromHost); // send out for processing. |
gatedClock | 2:08655e2bb776 | 357 | gcNewCommand = 0; // don't execute until next new command. |
gatedClock | 2:08655e2bb776 | 358 | } // execute once per new command. |
gatedClock | 2:08655e2bb776 | 359 | Thread::wait(THREAD_0_WAIT); // multitasking. |
gatedClock | 2:08655e2bb776 | 360 | } // processIncomingSerial |
gatedClock | 2:08655e2bb776 | 361 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 362 | void processOutgoingSerial(void) // prepare/transmit data to host. |
gatedClock | 2:08655e2bb776 | 363 | { |
gatedClock | 2:08655e2bb776 | 364 | int dLoop; // loop index. |
gatedClock | 2:08655e2bb776 | 365 | |
gatedClock | 2:08655e2bb776 | 366 | gqToHostEvent = qToHost.get(1); // check for reply back to host. |
gatedClock | 2:08655e2bb776 | 367 | |
gatedClock | 2:08655e2bb776 | 368 | // if new reply to host: |
gatedClock | 2:08655e2bb776 | 369 | if (gqToHostEvent.status == osEventMessage) |
gatedClock | 2:08655e2bb776 | 370 | { |
gatedClock | 2:08655e2bb776 | 371 | // bring it in from the queue. |
gatedClock | 2:08655e2bb776 | 372 | gpToHost = (tToHost *) gqToHostEvent.value.p; |
gatedClock | 2:08655e2bb776 | 373 | if (!gpToHost) error("\n\r processOutgoingSerial : FATAL null gpToHost pointer. \n\r"); |
gatedClock | 2:08655e2bb776 | 374 | |
gatedClock | 2:08655e2bb776 | 375 | // clear outgoing buffer. |
gatedClock | 2:08655e2bb776 | 376 | for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialToHost[dLoop] = 0; |
gatedClock | 2:08655e2bb776 | 377 | |
gatedClock | 2:08655e2bb776 | 378 | // the commands from the host were |
gatedClock | 2:08655e2bb776 | 379 | // looped-back into the to-host struct, |
gatedClock | 2:08655e2bb776 | 380 | // make use of them here. |
gatedClock | 2:08655e2bb776 | 381 | |
gatedClock | 2:08655e2bb776 | 382 | if (gpToHost->cCommand == HCMD_GETREG) // reading from a register. |
gatedClock | 2:08655e2bb776 | 383 | { |
gatedClock | 2:08655e2bb776 | 384 | gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); |
gatedClock | 2:08655e2bb776 | 385 | gpcSerialToHost[1] = binary_to_ascii_nibble( gpToHost->cRegisterID); |
gatedClock | 2:08655e2bb776 | 386 | gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F); |
gatedClock | 2:08655e2bb776 | 387 | gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F); |
gatedClock | 2:08655e2bb776 | 388 | gpcSerialToHost[4] = '\n'; // signals end of transfer. |
gatedClock | 2:08655e2bb776 | 389 | |
gatedClock | 2:08655e2bb776 | 390 | // transmit to the host. |
gatedClock | 2:08655e2bb776 | 391 | serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); |
gatedClock | 2:08655e2bb776 | 392 | gdRoundTrip--; // expected reply sent to host. |
gatedClock | 2:08655e2bb776 | 393 | } |
gatedClock | 2:08655e2bb776 | 394 | |
gatedClock | 2:08655e2bb776 | 395 | if (gpToHost->cCommand == HCMD_GETMM) // reading from main-memory. |
gatedClock | 2:08655e2bb776 | 396 | { |
gatedClock | 2:08655e2bb776 | 397 | gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); |
gatedClock | 2:08655e2bb776 | 398 | gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F); |
gatedClock | 2:08655e2bb776 | 399 | gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F); |
gatedClock | 2:08655e2bb776 | 400 | gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 4) & 0x0F); |
gatedClock | 2:08655e2bb776 | 401 | gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 0) & 0x0F); |
gatedClock | 2:08655e2bb776 | 402 | gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 4) & 0x0F); |
gatedClock | 2:08655e2bb776 | 403 | gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 0) & 0x0F); |
gatedClock | 2:08655e2bb776 | 404 | gpcSerialToHost[7] = '\n'; // signals end of transfer. |
gatedClock | 2:08655e2bb776 | 405 | |
gatedClock | 2:08655e2bb776 | 406 | // transmit to the host. |
gatedClock | 2:08655e2bb776 | 407 | serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); |
gatedClock | 2:08655e2bb776 | 408 | gdRoundTrip--; // expected reply sent to host. |
gatedClock | 2:08655e2bb776 | 409 | } |
gatedClock | 2:08655e2bb776 | 410 | mPoolToHost.free(gpToHost); // done with this queue entry. |
gatedClock | 2:08655e2bb776 | 411 | gpToHost = NULL; // clear pointer. |
gatedClock | 2:08655e2bb776 | 412 | } // if new reply to host. |
gatedClock | 2:08655e2bb776 | 413 | } // processOutgoingSerial. |
gatedClock | 2:08655e2bb776 | 414 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 415 | // the pcSendBuffer and pcReceiveBuffer arrays are not used by this function, |
gatedClock | 2:08655e2bb776 | 416 | // but they are declared by this function, and their pointers are passed |
gatedClock | 2:08655e2bb776 | 417 | // down to the mmSPI library for its use of them. |
gatedClock | 2:08655e2bb776 | 418 | // note- the prefix 'pc' means 'pointer of type character', not 'personal computer'. |
gatedClock | 2:08655e2bb776 | 419 | |
gatedClock | 2:08655e2bb776 | 420 | void SPIprocessingThread(void const *args) // process host-commands via SPI. |
gatedClock | 2:08655e2bb776 | 421 | { |
gatedClock | 2:08655e2bb776 | 422 | char pcSendBuffer [SPI_BYTES]; // SPI send buffer. |
gatedClock | 2:08655e2bb776 | 423 | char pcReceiveBuffer[SPI_BYTES]; // SPI receive buffer. |
gatedClock | 2:08655e2bb776 | 424 | int dHeartbeat; // heartbeat counter. |
gatedClock | 2:08655e2bb776 | 425 | int dMemoryRead; // read main-memory into this. |
gatedClock | 2:08655e2bb776 | 426 | int dLoop; // loop index. |
gatedClock | 2:08655e2bb776 | 427 | osEvent qFromHostEvent; // incoming message event. |
gatedClock | 2:08655e2bb776 | 428 | tFromHost * pFromHost; // message structure. |
gatedClock | 2:08655e2bb776 | 429 | tToHost * gpToHost; // message structure. |
gatedClock | 2:08655e2bb776 | 430 | mmSPI * pSPI; // SPI. |
gatedClock | 2:08655e2bb776 | 431 | |
gatedClock | 2:08655e2bb776 | 432 | pFromHost = NULL; // NULL pointers. |
gatedClock | 2:08655e2bb776 | 433 | gpToHost = NULL; |
gatedClock | 2:08655e2bb776 | 434 | pSPI = NULL; |
gatedClock | 2:08655e2bb776 | 435 | dHeartbeat = 0; // clear variables. |
gatedClock | 2:08655e2bb776 | 436 | dMemoryRead = 0; |
gatedClock | 2:08655e2bb776 | 437 | dLoop = 0; |
gatedClock | 2:08655e2bb776 | 438 | // clear SPI vectors. |
gatedClock | 2:08655e2bb776 | 439 | for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcSendBuffer [dLoop] = 0; |
gatedClock | 2:08655e2bb776 | 440 | for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcReceiveBuffer[dLoop] = 0; |
gatedClock | 2:08655e2bb776 | 441 | |
gatedClock | 2:08655e2bb776 | 442 | pSPI = new mmSPI; // SPI allocation. |
gatedClock | 2:08655e2bb776 | 443 | if (!pSPI) error("\n\r SPIprocessingThread : FATAL malloc error for pSPI. \n\r"); |
gatedClock | 2:08655e2bb776 | 444 | |
gatedClock | 2:08655e2bb776 | 445 | pSPI->setSendBuffer (pcSendBuffer); // set SPI send buffer. |
gatedClock | 2:08655e2bb776 | 446 | pSPI->setReceiveBuffer(pcReceiveBuffer); // set SPI receive buffer. |
gatedClock | 2:08655e2bb776 | 447 | pSPI->setNumberOfBytes(SPI_BYTES); // set SPI number of bytes. |
gatedClock | 2:08655e2bb776 | 448 | pSPI->setSPIfrequency (SPI_HZ); // set SPI clock frequency. |
gatedClock | 2:08655e2bb776 | 449 | |
gatedClock | 2:08655e2bb776 | 450 | while(1) // thread loop. |
gatedClock | 2:08655e2bb776 | 451 | { |
gatedClock | 2:08655e2bb776 | 452 | qFromHostEvent = qFromHost.get(1); // check for incoming host command. |
gatedClock | 2:08655e2bb776 | 453 | |
gatedClock | 2:08655e2bb776 | 454 | // if new host command: |
gatedClock | 2:08655e2bb776 | 455 | if (qFromHostEvent.status == osEventMessage) |
gatedClock | 2:08655e2bb776 | 456 | { |
gatedClock | 2:08655e2bb776 | 457 | // bring it in from the queue. |
gatedClock | 2:08655e2bb776 | 458 | pFromHost = (tFromHost *) qFromHostEvent.value.p; |
gatedClock | 2:08655e2bb776 | 459 | if (!pFromHost) error("\n\r SPIprocessingThread : FATAL null pFromHost pointer. \n\r"); |
gatedClock | 2:08655e2bb776 | 460 | |
gatedClock | 2:08655e2bb776 | 461 | switch(pFromHost->cCommand) // host command decode. |
gatedClock | 2:08655e2bb776 | 462 | { |
gatedClock | 2:08655e2bb776 | 463 | case HCMD_SETREG : // set CPU register. |
gatedClock | 2:08655e2bb776 | 464 | { |
gatedClock | 2:08655e2bb776 | 465 | switch(pFromHost->cRegisterID) // which register to write to. |
gatedClock | 2:08655e2bb776 | 466 | { |
gatedClock | 2:08655e2bb776 | 467 | case CPU_REG_0 : {pSPI->write_register(CPU_REG_0 , pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 468 | case CPU_REG_1 : {pSPI->write_register(CPU_REG_1 , pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 469 | case CPU_REG_2 : {pSPI->write_register(CPU_REG_2 , pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 470 | case CPU_REG_3 : {pSPI->write_register(CPU_REG_3 , pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 471 | case CPU_REG_PC : {pSPI->write_register(CPU_REG_PC, pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 472 | default : {break;} |
gatedClock | 2:08655e2bb776 | 473 | } // which register to write to. |
gatedClock | 2:08655e2bb776 | 474 | break; |
gatedClock | 2:08655e2bb776 | 475 | } // set CPU register. |
gatedClock | 2:08655e2bb776 | 476 | |
gatedClock | 2:08655e2bb776 | 477 | case HCMD_SETIR: // set instruction register. |
gatedClock | 2:08655e2bb776 | 478 | { |
gatedClock | 2:08655e2bb776 | 479 | pSPI->write_IR(pFromHost->cIRValueH, pFromHost->cIRValueL); |
gatedClock | 2:08655e2bb776 | 480 | break; |
gatedClock | 2:08655e2bb776 | 481 | } // set instruction register. |
gatedClock | 2:08655e2bb776 | 482 | |
gatedClock | 2:08655e2bb776 | 483 | case HCMD_GETREG : // get CPU register. |
gatedClock | 2:08655e2bb776 | 484 | { |
gatedClock | 2:08655e2bb776 | 485 | gpToHost = mPoolToHost.alloc(); // allocate next pool entry. |
gatedClock | 2:08655e2bb776 | 486 | if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); |
gatedClock | 2:08655e2bb776 | 487 | clear_tToHost(gpToHost); // initialize structure. |
gatedClock | 2:08655e2bb776 | 488 | |
gatedClock | 2:08655e2bb776 | 489 | switch(pFromHost->cRegisterID) // which register to read from. |
gatedClock | 2:08655e2bb776 | 490 | { |
gatedClock | 2:08655e2bb776 | 491 | case CPU_REG_0 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_0 ); break;} |
gatedClock | 2:08655e2bb776 | 492 | case CPU_REG_1 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_1 ); break;} |
gatedClock | 2:08655e2bb776 | 493 | case CPU_REG_2 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_2 ); break;} |
gatedClock | 2:08655e2bb776 | 494 | case CPU_REG_3 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_3 ); break;} |
gatedClock | 2:08655e2bb776 | 495 | case CPU_REG_PC : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_PC); break;} |
gatedClock | 2:08655e2bb776 | 496 | case CPU_IR_H : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_H ); break;} |
gatedClock | 2:08655e2bb776 | 497 | case CPU_IR_L : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_L ); break;} |
gatedClock | 2:08655e2bb776 | 498 | default : {break;} |
gatedClock | 2:08655e2bb776 | 499 | } // which register to read from. |
gatedClock | 2:08655e2bb776 | 500 | |
gatedClock | 2:08655e2bb776 | 501 | // loop-back to host. |
gatedClock | 2:08655e2bb776 | 502 | gpToHost->cCommand = pFromHost->cCommand; |
gatedClock | 2:08655e2bb776 | 503 | gpToHost->cRegisterID = pFromHost->cRegisterID; |
gatedClock | 2:08655e2bb776 | 504 | |
gatedClock | 2:08655e2bb776 | 505 | qToHost.put(gpToHost); // send up for processing. |
gatedClock | 2:08655e2bb776 | 506 | break; |
gatedClock | 2:08655e2bb776 | 507 | } // get CPU register. |
gatedClock | 2:08655e2bb776 | 508 | |
gatedClock | 2:08655e2bb776 | 509 | case HCMD_SETMM : // do main-memory write. |
gatedClock | 2:08655e2bb776 | 510 | { |
gatedClock | 2:08655e2bb776 | 511 | pSPI->write_memory(pFromHost->cMMdataH, pFromHost->cMMdataL, pFromHost->cMMaddress); |
gatedClock | 2:08655e2bb776 | 512 | break; |
gatedClock | 2:08655e2bb776 | 513 | } // do main-memory write. |
gatedClock | 2:08655e2bb776 | 514 | |
gatedClock | 2:08655e2bb776 | 515 | case HCMD_GETMM : // do main-memory read. |
gatedClock | 2:08655e2bb776 | 516 | { |
gatedClock | 2:08655e2bb776 | 517 | gpToHost = mPoolToHost.alloc(); // allocate next pool entry. |
gatedClock | 2:08655e2bb776 | 518 | if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); |
gatedClock | 2:08655e2bb776 | 519 | clear_tToHost(gpToHost); // initialize structure. |
gatedClock | 2:08655e2bb776 | 520 | |
gatedClock | 2:08655e2bb776 | 521 | // read from CPU memory. |
gatedClock | 2:08655e2bb776 | 522 | dMemoryRead = pSPI->read_memory(pFromHost->cMMaddress); |
gatedClock | 2:08655e2bb776 | 523 | gpToHost->cMMdataH = (dMemoryRead >> 8) & 0xFF; |
gatedClock | 2:08655e2bb776 | 524 | gpToHost->cMMdataL = (dMemoryRead >> 0) & 0xFF; |
gatedClock | 2:08655e2bb776 | 525 | |
gatedClock | 2:08655e2bb776 | 526 | // loop-back to host. |
gatedClock | 2:08655e2bb776 | 527 | gpToHost->cCommand = pFromHost->cCommand; |
gatedClock | 2:08655e2bb776 | 528 | gpToHost->cMMaddress = pFromHost->cMMaddress; |
gatedClock | 2:08655e2bb776 | 529 | |
gatedClock | 2:08655e2bb776 | 530 | qToHost.put(gpToHost); // send up for processing. |
gatedClock | 2:08655e2bb776 | 531 | break; |
gatedClock | 2:08655e2bb776 | 532 | } // do main-memory read. |
gatedClock | 2:08655e2bb776 | 533 | |
gatedClock | 2:08655e2bb776 | 534 | case HCMD_STEP : // step the CPU. |
gatedClock | 2:08655e2bb776 | 535 | { |
gatedClock | 2:08655e2bb776 | 536 | pSPI->step(); |
gatedClock | 2:08655e2bb776 | 537 | break; |
gatedClock | 2:08655e2bb776 | 538 | } // step the CPU. |
gatedClock | 2:08655e2bb776 | 539 | default : break; |
gatedClock | 2:08655e2bb776 | 540 | } // host command decode. |
gatedClock | 2:08655e2bb776 | 541 | mPoolFromHost.free(pFromHost); // done with this queue entry. |
gatedClock | 2:08655e2bb776 | 542 | pFromHost = NULL; // clear pointer. |
gatedClock | 2:08655e2bb776 | 543 | } // if new host command. |
gatedClock | 2:08655e2bb776 | 544 | |
gatedClock | 2:08655e2bb776 | 545 | gulSPIclkCount = pSPI->SPIClockCount(); // propagate to global variable. |
gatedClock | 2:08655e2bb776 | 546 | gulCPUclkCount = pSPI->CPUClockCount(); // propagate to global variable. |
gatedClock | 2:08655e2bb776 | 547 | |
gatedClock | 2:08655e2bb776 | 548 | // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 549 | dHeartbeat++; if (!(dHeartbeat % HB_MODULO)) led1 = !led1; |
gatedClock | 2:08655e2bb776 | 550 | Thread::wait(THREAD_1_WAIT); // cooperative multitasking. |
gatedClock | 2:08655e2bb776 | 551 | } // thread loop. |
gatedClock | 2:08655e2bb776 | 552 | } // SPIprocessingThread. |
gatedClock | 2:08655e2bb776 | 553 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 554 | void diagnosticThread(void const *args) // LCD and LED notifications. |
gatedClock | 2:08655e2bb776 | 555 | { |
gatedClock | 2:08655e2bb776 | 556 | int dHeartbeat; // heartbeat counter. |
gatedClock | 2:08655e2bb776 | 557 | |
gatedClock | 2:08655e2bb776 | 558 | dHeartbeat = 0; // initialize. |
gatedClock | 2:08655e2bb776 | 559 | led3 = 0; // initialize. |
gatedClock | 2:08655e2bb776 | 560 | |
gatedClock | 2:08655e2bb776 | 561 | while(1) // thread loop. |
gatedClock | 2:08655e2bb776 | 562 | { |
gatedClock | 2:08655e2bb776 | 563 | // if message round trip |
gatedClock | 2:08655e2bb776 | 564 | // count not consistent. |
gatedClock | 2:08655e2bb776 | 565 | if (gdRoundTrip > 1025 || gdRoundTrip < 1024) led3 = 1; |
gatedClock | 2:08655e2bb776 | 566 | |
gatedClock | 2:08655e2bb776 | 567 | lcd.cls(); // clear LCD display. |
gatedClock | 2:08655e2bb776 | 568 | LCD1; // lcd line 1. |
gatedClock | 2:08655e2bb776 | 569 | lcd.printf(" USB DEV CLASS PROJECT"); |
gatedClock | 2:08655e2bb776 | 570 | |
gatedClock | 2:08655e2bb776 | 571 | LCD2; // lcd line 2. |
gatedClock | 2:08655e2bb776 | 572 | lcd.printf(" %11lu = SPI clocks",gulSPIclkCount); |
gatedClock | 2:08655e2bb776 | 573 | |
gatedClock | 2:08655e2bb776 | 574 | LCD3; // lcd line 3. |
gatedClock | 2:08655e2bb776 | 575 | lcd.printf(" %11lu = CPU clocks",gulCPUclkCount); |
gatedClock | 2:08655e2bb776 | 576 | |
gatedClock | 2:08655e2bb776 | 577 | dHeartbeat++; // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 578 | if (!(dHeartbeat % HB_MODULO)) led2 = !led2; |
gatedClock | 2:08655e2bb776 | 579 | Thread::wait(THREAD_2_WAIT); // multitasking. |
gatedClock | 2:08655e2bb776 | 580 | } // thread loop. |
gatedClock | 2:08655e2bb776 | 581 | } // diagnosticThread. |
gatedClock | 2:08655e2bb776 | 582 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 583 | char ascii_nibble_to_binary(char cAscii) // ascii nibble -> binary. |
gatedClock | 2:08655e2bb776 | 584 | { |
gatedClock | 2:08655e2bb776 | 585 | char cBinary; // converted value. |
gatedClock | 2:08655e2bb776 | 586 | |
gatedClock | 2:08655e2bb776 | 587 | switch(cAscii) |
gatedClock | 2:08655e2bb776 | 588 | { |
gatedClock | 2:08655e2bb776 | 589 | case 'F' : {cBinary = 15; break;} |
gatedClock | 2:08655e2bb776 | 590 | case 'E' : {cBinary = 14; break;} |
gatedClock | 2:08655e2bb776 | 591 | case 'D' : {cBinary = 13; break;} |
gatedClock | 2:08655e2bb776 | 592 | case 'C' : {cBinary = 12; break;} |
gatedClock | 2:08655e2bb776 | 593 | case 'B' : {cBinary = 11; break;} |
gatedClock | 2:08655e2bb776 | 594 | case 'A' : {cBinary = 10; break;} |
gatedClock | 2:08655e2bb776 | 595 | case 'f' : {cBinary = 15; break;} |
gatedClock | 2:08655e2bb776 | 596 | case 'e' : {cBinary = 14; break;} |
gatedClock | 2:08655e2bb776 | 597 | case 'd' : {cBinary = 13; break;} |
gatedClock | 2:08655e2bb776 | 598 | case 'c' : {cBinary = 12; break;} |
gatedClock | 2:08655e2bb776 | 599 | case 'b' : {cBinary = 11; break;} |
gatedClock | 2:08655e2bb776 | 600 | case 'a' : {cBinary = 10; break;} |
gatedClock | 2:08655e2bb776 | 601 | case '9' : {cBinary = 9; break;} |
gatedClock | 2:08655e2bb776 | 602 | case '8' : {cBinary = 8; break;} |
gatedClock | 2:08655e2bb776 | 603 | case '7' : {cBinary = 7; break;} |
gatedClock | 2:08655e2bb776 | 604 | case '6' : {cBinary = 6; break;} |
gatedClock | 2:08655e2bb776 | 605 | case '5' : {cBinary = 5; break;} |
gatedClock | 2:08655e2bb776 | 606 | case '4' : {cBinary = 4; break;} |
gatedClock | 2:08655e2bb776 | 607 | case '3' : {cBinary = 3; break;} |
gatedClock | 2:08655e2bb776 | 608 | case '2' : {cBinary = 2; break;} |
gatedClock | 2:08655e2bb776 | 609 | case '1' : {cBinary = 1; break;} |
gatedClock | 2:08655e2bb776 | 610 | case '0' : {cBinary = 0; break;} |
gatedClock | 2:08655e2bb776 | 611 | default : {cBinary = 0; break;} |
gatedClock | 2:08655e2bb776 | 612 | } // switch(cAscii). |
gatedClock | 2:08655e2bb776 | 613 | return(cBinary); // return the binary. |
gatedClock | 2:08655e2bb776 | 614 | } // ascii_nibble_to_binary. |
gatedClock | 2:08655e2bb776 | 615 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 616 | char binary_to_ascii_nibble(char cBinary) // binary -> ascii nibble. |
gatedClock | 2:08655e2bb776 | 617 | { |
gatedClock | 2:08655e2bb776 | 618 | char cAscii; // converted value. |
gatedClock | 2:08655e2bb776 | 619 | |
gatedClock | 2:08655e2bb776 | 620 | switch(cBinary) |
gatedClock | 2:08655e2bb776 | 621 | { |
gatedClock | 2:08655e2bb776 | 622 | case 15 : {cAscii = 'F'; break;} |
gatedClock | 2:08655e2bb776 | 623 | case 14 : {cAscii = 'E'; break;} |
gatedClock | 2:08655e2bb776 | 624 | case 13 : {cAscii = 'D'; break;} |
gatedClock | 2:08655e2bb776 | 625 | case 12 : {cAscii = 'C'; break;} |
gatedClock | 2:08655e2bb776 | 626 | case 11 : {cAscii = 'B'; break;} |
gatedClock | 2:08655e2bb776 | 627 | case 10 : {cAscii = 'A'; break;} |
gatedClock | 2:08655e2bb776 | 628 | case 9 : {cAscii = '9'; break;} |
gatedClock | 2:08655e2bb776 | 629 | case 8 : {cAscii = '8'; break;} |
gatedClock | 2:08655e2bb776 | 630 | case 7 : {cAscii = '7'; break;} |
gatedClock | 2:08655e2bb776 | 631 | case 6 : {cAscii = '6'; break;} |
gatedClock | 2:08655e2bb776 | 632 | case 5 : {cAscii = '5'; break;} |
gatedClock | 2:08655e2bb776 | 633 | case 4 : {cAscii = '4'; break;} |
gatedClock | 2:08655e2bb776 | 634 | case 3 : {cAscii = '3'; break;} |
gatedClock | 2:08655e2bb776 | 635 | case 2 : {cAscii = '2'; break;} |
gatedClock | 2:08655e2bb776 | 636 | case 1 : {cAscii = '1'; break;} |
gatedClock | 2:08655e2bb776 | 637 | case 0 : {cAscii = '0'; break;} |
gatedClock | 2:08655e2bb776 | 638 | default : {cAscii = '0'; break;} |
gatedClock | 2:08655e2bb776 | 639 | } // switch(cBinary). |
gatedClock | 2:08655e2bb776 | 640 | return(cAscii); // return the binary. |
gatedClock | 2:08655e2bb776 | 641 | } // binary_to_ascii_nibble. |
gatedClock | 2:08655e2bb776 | 642 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 643 | void clear_tFromHost(tFromHost * ptFromHost)// clear structure. |
gatedClock | 2:08655e2bb776 | 644 | { |
gatedClock | 2:08655e2bb776 | 645 | ptFromHost->cCommand = 0x00; |
gatedClock | 2:08655e2bb776 | 646 | ptFromHost->cRegisterID = 0x00; |
gatedClock | 2:08655e2bb776 | 647 | ptFromHost->cRegisterValue = 0x00; |
gatedClock | 2:08655e2bb776 | 648 | ptFromHost->cIRValueH = 0x00; |
gatedClock | 2:08655e2bb776 | 649 | ptFromHost->cIRValueL = 0x00; |
gatedClock | 2:08655e2bb776 | 650 | ptFromHost->cMMaddress = 0x00; |
gatedClock | 2:08655e2bb776 | 651 | ptFromHost->cMMdataH = 0x00; |
gatedClock | 2:08655e2bb776 | 652 | ptFromHost->cMMdataL = 0x00; |
gatedClock | 2:08655e2bb776 | 653 | } // clear_tFromHost. |
gatedClock | 2:08655e2bb776 | 654 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 655 | void clear_tToHost(tToHost * ptToHost) // clear structure. |
gatedClock | 2:08655e2bb776 | 656 | { |
gatedClock | 2:08655e2bb776 | 657 | ptToHost->cCommand = 0x00; |
gatedClock | 2:08655e2bb776 | 658 | ptToHost->cRegisterID = 0x00; |
gatedClock | 2:08655e2bb776 | 659 | ptToHost->cRegisterValue = 0x00; |
gatedClock | 2:08655e2bb776 | 660 | ptToHost->cMMaddress = 0x00; |
gatedClock | 2:08655e2bb776 | 661 | ptToHost->cMMdataH = 0x00; |
gatedClock | 2:08655e2bb776 | 662 | ptToHost->cMMdataL = 0x00; |
gatedClock | 2:08655e2bb776 | 663 | } // clear_tToHost. |
gatedClock | 2:08655e2bb776 | 664 | /*----------------------------------------------//----------------------------*/ |