├── .gitignore ├── ArduinoGotchi.ino ├── LICENSE ├── README.md ├── TamaRomConvert.class ├── TamaRomConvert.java ├── bitmaps.h ├── cpu.c ├── cpu.h ├── hal.h ├── hal_types.h ├── hardcoded_state.h ├── hw.c ├── hw.h ├── images ├── Compile_and_upload.png ├── TamaP1_devices.jpg └── circuit_diagram_01.png ├── tamalib.c └── tamalib.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | rom.bin 3 | rom_12bit.h 4 | -------------------------------------------------------------------------------- /ArduinoGotchi.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ArduinoGotchi - A real Tamagotchi emulator for Arduino UNO 3 | * 4 | * Copyright (C) 2022 Gary Kwok 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include "tamalib.h" 25 | #include "hw.h" 26 | #include "bitmaps.h" 27 | #include "hardcoded_state.h" 28 | 29 | /***** U8g2 SSD1306 Library Setting *****/ 30 | #define DISPLAY_I2C_ADDRESS 0x3C 31 | #define SCREEN_WIDTH 128 // OLED display width, in pixels 32 | #define SCREEN_HEIGHT 64 // OLED display height, in pixels 33 | /****************************************/ 34 | 35 | /***** Tama Setting and Features *****/ 36 | #define TAMA_DISPLAY_FRAMERATE 3 // 3 is optimal for Arduino UNO 37 | #define ENABLE_TAMA_SOUND 38 | #define ENABLE_AUTO_SAVE_STATUS 39 | #define AUTO_SAVE_MINUTES 60 // Auto save for every hour (to preserve EEPROM lifespan) 40 | #define ENABLE_LOAD_STATE_FROM_EEPROM 41 | //#define ENABLE_DUMP_STATE_TO_SERIAL_WHEN_START 42 | //#define ENABLE_SERIAL_DEBUG_INPUT 43 | //#define ENABLE_LOAD_HARCODED_STATE_WHEN_START 44 | /***************************/ 45 | 46 | /***** Set display orientation, U8G2_MIRROR_VERTICAL is not supported *****/ 47 | #define U8G2_LAYOUT_NORMAL 48 | //#define U8G2_LAYOUT_ROTATE_180 49 | //#define U8G2_LAYOUT_MIRROR 50 | /**************************************************************************/ 51 | 52 | #ifdef U8G2_LAYOUT_NORMAL 53 | U8G2_SSD1306_128X64_NONAME_2_HW_I2C display(U8G2_R0); 54 | #endif 55 | 56 | #ifdef U8G2_LAYOUT_ROTATE_180 57 | U8G2_SSD1306_128X64_NONAME_2_HW_I2C display(U8G2_R2); 58 | #endif 59 | 60 | #ifdef U8G2_LAYOUT_MIRROR 61 | U8G2_SSD1306_128X64_NONAME_2_HW_I2C display(U8G2_MIRROR); 62 | #endif 63 | 64 | /**** TamaLib Specific Variables ****/ 65 | static uint16_t current_freq = 0; 66 | static bool_t matrix_buffer[LCD_HEIGHT][LCD_WIDTH/8] = {{0}}; 67 | static byte runOnceBool = 0; 68 | static bool_t icon_buffer[ICON_NUM] = {0}; 69 | static cpu_state_t cpuState; 70 | static unsigned long lastSaveTimestamp = 0; 71 | /************************************/ 72 | 73 | static void hal_halt(void) { 74 | //Serial.println("Halt!"); 75 | } 76 | 77 | static void hal_log(log_level_t level, char *buff, ...) { 78 | Serial.println(buff); 79 | } 80 | 81 | static void hal_sleep_until(timestamp_t ts) { 82 | //int32_t remaining = (int32_t) (ts - hal_get_timestamp()); 83 | //if (remaining > 0) { 84 | //delayMicroseconds(1); 85 | //delay(1); 86 | //} 87 | } 88 | 89 | static timestamp_t hal_get_timestamp(void) { 90 | return millis() * 1000; 91 | } 92 | 93 | static void hal_update_screen(void) { 94 | displayTama(); 95 | } 96 | 97 | static void hal_set_lcd_matrix(u8_t x, u8_t y, bool_t val) { 98 | uint8_t mask; 99 | if (val) { 100 | mask = 0b10000000 >> (x % 8); 101 | matrix_buffer[y][x/8] = matrix_buffer[y][x/8] | mask; 102 | } else { 103 | mask = 0b01111111; 104 | for(byte i=0;i<(x % 8);i++) { 105 | mask = (mask >> 1) | 0b10000000; 106 | } 107 | matrix_buffer[y][x/8] = matrix_buffer[y][x/8] & mask; 108 | } 109 | } 110 | 111 | static void hal_set_lcd_icon(u8_t icon, bool_t val) { 112 | icon_buffer[icon] = val; 113 | } 114 | 115 | static void hal_set_frequency(u32_t freq) { 116 | current_freq = freq; 117 | } 118 | 119 | static void hal_play_frequency(bool_t en) { 120 | #ifdef ENABLE_TAMA_SOUND 121 | if (en) { 122 | tone(9, current_freq); 123 | } else { 124 | noTone(9); 125 | } 126 | #endif 127 | } 128 | 129 | static bool_t button4state = 0; 130 | 131 | static int hal_handler(void) { 132 | #ifdef ENABLE_SERIAL_DEBUG_INPUT 133 | if (Serial.available() > 0) { 134 | int incomingByte = Serial.read(); 135 | Serial.println(incomingByte, DEC); 136 | if (incomingByte==49) { 137 | hw_set_button(BTN_LEFT, BTN_STATE_PRESSED ); 138 | } else if (incomingByte==50) { 139 | hw_set_button(BTN_LEFT, BTN_STATE_RELEASED ); 140 | } else if (incomingByte==51) { 141 | hw_set_button(BTN_MIDDLE, BTN_STATE_PRESSED ); 142 | } else if (incomingByte==52) { 143 | hw_set_button(BTN_MIDDLE, BTN_STATE_RELEASED ); 144 | } else if (incomingByte==53) { 145 | hw_set_button(BTN_RIGHT, BTN_STATE_PRESSED ); 146 | } else if (incomingByte==54) { 147 | hw_set_button(BTN_RIGHT, BTN_STATE_RELEASED ); 148 | } 149 | } 150 | #else 151 | if (digitalRead(2) == HIGH) { 152 | hw_set_button(BTN_LEFT, BTN_STATE_PRESSED ); 153 | } else { 154 | hw_set_button(BTN_LEFT, BTN_STATE_RELEASED ); 155 | } 156 | if (digitalRead(3) == HIGH) { 157 | hw_set_button(BTN_MIDDLE, BTN_STATE_PRESSED ); 158 | } else { 159 | hw_set_button(BTN_MIDDLE, BTN_STATE_RELEASED ); 160 | } 161 | if (digitalRead(4) == HIGH) { 162 | hw_set_button(BTN_RIGHT, BTN_STATE_PRESSED ); 163 | } else { 164 | hw_set_button(BTN_RIGHT, BTN_STATE_RELEASED ); 165 | } 166 | #ifdef ENABLE_AUTO_SAVE_STATUS 167 | if (digitalRead(5) == HIGH) { 168 | if (button4state==0) { 169 | saveStateToEEPROM(); 170 | } 171 | button4state = 1; 172 | } else { 173 | button4state = 0; 174 | } 175 | #endif 176 | #endif 177 | return 0; 178 | } 179 | 180 | static hal_t hal = { 181 | .halt = &hal_halt, 182 | .log = &hal_log, 183 | .sleep_until = &hal_sleep_until, 184 | .get_timestamp = &hal_get_timestamp, 185 | .update_screen = &hal_update_screen, 186 | .set_lcd_matrix = &hal_set_lcd_matrix, 187 | .set_lcd_icon = &hal_set_lcd_icon, 188 | .set_frequency = &hal_set_frequency, 189 | .play_frequency = &hal_play_frequency, 190 | .handler = &hal_handler, 191 | }; 192 | 193 | void drawTriangle(uint8_t x, uint8_t y) { 194 | //display.drawLine(x,y,x+6,y); 195 | display.drawLine(x+1,y+1,x+5,y+1); 196 | display.drawLine(x+2,y+2,x+4,y+2); 197 | display.drawLine(x+3,y+3,x+3,y+3); 198 | } 199 | 200 | void drawTamaRow(uint8_t tamaLCD_y, uint8_t ActualLCD_y, uint8_t thick) { 201 | uint8_t i; 202 | for (i = 0; i < LCD_WIDTH; i++) { 203 | uint8_t mask = 0b10000000; 204 | mask = mask >> (i % 8); 205 | if ( (matrix_buffer[tamaLCD_y][i/8] & mask) != 0) { 206 | display.drawBox(i+i+i+16,ActualLCD_y,2,thick); 207 | } 208 | } 209 | } 210 | 211 | void drawTamaSelection(uint8_t y) { 212 | uint8_t i; 213 | for(i=0;i<7;i++) { 214 | if (icon_buffer[i]) drawTriangle(i*16+5,y); 215 | display.drawXBMP(i*16+4,y+6,16,9,bitmaps+i*18); 216 | } 217 | if (icon_buffer[7]) { 218 | drawTriangle(7*16+5,y); 219 | display.drawXBMP(7*16+4,y+6,16,9,bitmaps+7*18); 220 | } 221 | } 222 | 223 | void displayTama() { 224 | uint8_t j; 225 | display.firstPage(); 226 | #ifdef U8G2_LAYOUT_ROTATE_180 227 | drawTamaSelection(49); 228 | display.nextPage(); 229 | 230 | for (j = 11; j < LCD_HEIGHT; j++) { 231 | drawTamaRow(j,j+j+j,2); 232 | } 233 | display.nextPage(); 234 | 235 | for (j = 5; j <= 10; j++) { 236 | if (j==5) { 237 | drawTamaRow(j,j+j+j+1,1); 238 | } else { 239 | drawTamaRow(j,j+j+j,2); 240 | } 241 | } 242 | display.nextPage(); 243 | 244 | for (j = 0; j <= 5; j++) { 245 | if (j==5) { 246 | drawTamaRow(j,j+j+j,1); 247 | } else { 248 | drawTamaRow(j,j+j+j,2); 249 | } 250 | } 251 | display.nextPage(); 252 | #else 253 | for (j = 0; j < LCD_HEIGHT; j++) { 254 | if (j!=5) drawTamaRow(j,j+j+j,2); 255 | if (j==5) { 256 | drawTamaRow(j,j+j+j,1); 257 | display.nextPage(); 258 | drawTamaRow(j,j+j+j+1,1); 259 | } 260 | if (j==10) display.nextPage(); 261 | } 262 | display.nextPage(); 263 | drawTamaSelection(49); 264 | display.nextPage(); 265 | #endif 266 | } 267 | 268 | #ifdef ENABLE_DUMP_STATE_TO_SERIAL_WHEN_START 269 | void dumpStateToSerial() { 270 | uint16_t i, count=0; 271 | char tmp[10]; 272 | cpu_get_state(&cpuState); 273 | u4_t *memTemp = cpuState.memory; 274 | uint8_t *cpuS = (uint8_t *)&cpuState; 275 | 276 | Serial.println(""); 277 | Serial.println("static const uint8_t hardcodedState[] PROGMEM = {"); 278 | for(i=0;i (AUTO_SAVE_MINUTES * 60 * 1000)) { 405 | lastSaveTimestamp = millis(); 406 | saveStateToEEPROM(); 407 | } 408 | #endif 409 | } 410 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ArduinoGotchi - A real Tamagotchi emulator for Arduino UNO 2 | 3 | ## Synopsis 4 | 5 | **ArduinoGotchi** is a real [Tamagotchi P1](https://tamagotchi.fandom.com/wiki/Tamagotchi_(1996_Pet)) emulator running in Arduino UNO hardware. The emulation core is based on [TamaLib](https://github.com/jcrona/tamalib) with intensive optimization to make it fit into UNO's hardware that only comes with 32K Flash 2K RAM. 6 | 7 | ![Tamagotchi P1 Actual Devices](../main/images/TamaP1_devices.jpg) 8 | 9 | ### Demonstration (click the photo to watch) 10 | [![Demo 1](https://img.youtube.com/vi/MJvAr_od06M/0.jpg)](https://www.youtube.com/watch?v=MJvAr_od06M) 11 | [![Demo 2](https://img.youtube.com/vi/ab3_0PLWAnc/0.jpg)](https://www.youtube.com/watch?v=ab3_0PLWAnc) 12 | 13 | ## How to build 14 | 15 | ### Prerequisites 16 | 17 | - **Git** - command line tool, please follows [Getting started installing Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 18 | - **Arduino IDE** - [Download and Install](https://www.arduino.cc/en/software) 19 | - **Java 8 Runtime** - [Download and install](https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html) 20 | - **Parts** 21 | - Arduino UNO (also compatible with Arduino Micro, Arduino Nano, Arduino Mega) 22 | - 1K resistor x 3 23 | - Push button x 3 24 | - Buzzer 25 | - SSD1306 I2C OLED 128x64 26 | - **Tamagotchi P1 ROM** - ArduinoGotchi being an emulator, it requires a compatible Tamagotchi P1 ROM named 27 | **rom.bin** and place it in the project folder. Due to the copyright issue, Rom file is not provided, you have to find it yourself 28 | - Clone this repository from Github into your PC, run the following commands: 29 | ``` 30 | git clone https://github.com/GaryZ88/ArduinoGotchi 31 | cd ArduinoGotchi 32 | ``` 33 | 34 | ### Preparing a ROM data file 35 | - Put the **rom.bin** in the project folder, i.e. /ArduinoGotchi/ 36 | - Run the below commands, if success, it will generate a file named "**rom_12bit.h**" in the project folder 37 | ``` 38 | cd ArduinoGotchi 39 | java TamaRomConvert rom.bin 40 | ``` 41 | 42 | ### Compile and Run 43 | - Compose the electronic parts, please follow the circult diagram below 44 | - Launch Arduino IDE 45 | - Open "ArduinoGotchi.ino" in the project folder 46 | - Connect your Arduino UNO to PC/Mac with USB cable 47 | - Select your board 48 | - Main Menu -> Tools -> Board -> Arduino AVR Boards -> Arduino UNO 49 | - Install U8g2 library 50 | - Main Menu -> Sketch -> Include Library -> Manage Libraries 51 | - Search "U8g2" and install 52 | - Click the "Upload" button 53 | ![Compile and upload success](../main/images/Compile_and_upload.png) 54 | 55 | ### Additional notes 56 | - To activate your pet, you have to configure the clock by pressing the middle button. Otherwise, your pet will not alive. 57 | - The emulator will save the game status for every 60 mintues. 58 | - The speed of the emulator is a bit slower than the actual Tamagotchi device, still, it is fun. 59 | - There are a few settings in the main program (**ArduinoGotchi.ino**) that you can adjust to fit your need: 60 | ``` 61 | /***** U8g2 SSD1306 Library Setting *****/ 62 | #define DISPLAY_I2C_ADDRESS 0x3C 63 | #define SCREEN_WIDTH 128 // OLED display width, in pixels 64 | #define SCREEN_HEIGHT 64 // OLED display height, in pixels 65 | /****************************************/ 66 | 67 | /***** Tama Setting and Features *****/ 68 | #define TAMA_DISPLAY_FRAMERATE 3 // 3 is optimal for Arduino UNO 69 | #define ENABLE_TAMA_SOUND 70 | #define ENABLE_AUTO_SAVE_STATUS 71 | #define AUTO_SAVE_MINUTES 60 // Auto save for every hour (to preserve EEPROM lifespan) 72 | #define ENABLE_LOAD_STATE_FROM_EEPROM 73 | //#define ENABLE_DUMP_STATE_TO_SERIAL_WHEN_START 74 | //#define ENABLE_SERIAL_DEBUG_INPUT 75 | //#define ENABLE_LOAD_HARCODED_STATE_WHEN_START 76 | /***************************/ 77 | 78 | /***** Set display orientation, U8G2_MIRROR_VERTICAL is not supported *****/ 79 | #define U8G2_LAYOUT_NORMAL 80 | //#define U8G2_LAYOUT_ROTATE_180 81 | //#define U8G2_LAYOUT_MIRROR 82 | /**************************************************************************/ 83 | ``` 84 | 85 | ### Circuit Diagram 86 | ![Circuit Diagram](../main/images/circuit_diagram_01.png) 87 | 88 | ### License 89 | ArduinoGotchi is distributed under the GPLv2 license. See the LICENSE file for more information. 90 | -------------------------------------------------------------------------------- /TamaRomConvert.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaryZ88/ArduinoGotchi/900b4192c450cb692b91690aea7658d4016d563d/TamaRomConvert.class -------------------------------------------------------------------------------- /TamaRomConvert.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedWriter; 2 | import java.io.FileOutputStream; 3 | import java.io.OutputStreamWriter; 4 | import java.nio.file.Files; 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | 8 | public class TamaRomConvert { 9 | private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); 10 | private static final String lineSeparator = System.getProperty("line.separator"); 11 | 12 | public static String byteToHex(byte b) { 13 | char[] hexChars = new char[2]; 14 | int v = b & 0xFF; 15 | hexChars[0] = HEX_ARRAY[v >>> 4]; 16 | hexChars[1] = HEX_ARRAY[v & 0x0F]; 17 | return new String(hexChars); 18 | } 19 | 20 | public static void main(String argv[]) { 21 | if (argv.length!=1) { 22 | System.out.println("Usage: java TamaRomConvert [Tamagotchi P1 ROM File]"); 23 | return; 24 | } 25 | String inFile = argv[0]; 26 | System.out.println("Reading Tamagotchi P1 ROM [" + inFile +"]...."); 27 | try { 28 | Path path = Paths.get(inFile); 29 | byte[] data = Files.readAllBytes(path); 30 | System.out.print("ROM Size: " + data.length); 31 | if (data.length==12288) { 32 | System.out.println(" - Correct size"); 33 | } else { 34 | System.out.println(" - Incorrect size! Expected: 12288 bytes"); 35 | return; 36 | } 37 | byte[] b = new byte[3]; 38 | BufferedWriter writer=null; 39 | writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("rom_12bit.h", false),"UTF-8")); 40 | writer.write("static const unsigned char g_program_b12[] PROGMEM = {" + lineSeparator); 41 | for (int i = 0; i < (data.length/4); i++) { 42 | // System.out.print(byteToHex(data[i]) + ","); 43 | if ((i % 6)==0) writer.write(" "); 44 | int v1 = data[i*4]; // 0F 45 | int v2 = data[i*4+1]; // A2 46 | int v3 = data[i*4+2]; // 0C 47 | int v4 = data[i*4+3]; // 87 48 | b[0] = (byte)(v1 << 4 | ((v2 >> 4) & 0xF)); 49 | b[1] = (byte)(((v2 & 0xF) << 4) | v3); 50 | b[2] = (byte)v4; 51 | writer.write("0x" + byteToHex(b[0]) + ","); 52 | writer.write("0x" + byteToHex(b[1]) + ","); 53 | writer.write("0x" + byteToHex(b[2]) + ","); 54 | writer.write(" "); 55 | if (((i+1) % 6)==0) { 56 | writer.write(lineSeparator); 57 | } 58 | } 59 | writer.write("};" + lineSeparator); 60 | writer.close(); 61 | System.out.println("[rom_12bit.h] header file generated successfully! Enjoy."); 62 | } catch (Exception e) { 63 | e.printStackTrace(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /bitmaps.h: -------------------------------------------------------------------------------- 1 | static const uint8_t bitmaps[] PROGMEM = { 2 | 0x20,0x00,0x10,0x00,0xFE,0x00,0xFB,0x01,0xFD,0x01,0xFF,0x01,0xFF,0x01,0xFE,0x00,0x6C,0x00, 3 | 0x10,0x00,0x82,0x00,0x38,0x00,0x7C,0x00,0x7D,0x01,0x7C,0x00,0x38,0x00,0x82,0x00,0x10,0x00, 4 | 0x04,0x00,0x06,0x00,0xFF,0x01,0x06,0x00,0x44,0x00,0xC0,0x00,0xFF,0x01,0xC0,0x00,0x40,0x00, 5 | 0xEE,0x00,0x11,0x01,0x00,0x01,0x02,0x01,0x07,0x01,0x82,0x00,0x40,0x00,0x28,0x00,0x10,0x00, 6 | 0x20,0x00,0x02,0x00,0x98,0x00,0x1C,0x00,0x64,0x00,0xFE,0x00,0xFE,0x00,0x8F,0x01,0xFF,0x01, 7 | 0x1C,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x5C,0x00,0x80,0x00,0x00,0x01, 8 | 0x1E,0x00,0x3F,0x00,0x33,0x00,0x2F,0x00,0x7F,0x00,0x3F,0x01,0x9F,0x00,0x3E,0x01,0x0C,0x00, 9 | 0x7C,0x00,0x82,0x00,0x11,0x01,0x11,0x01,0x11,0x01,0x01,0x01,0x11,0x01,0x82,0x00,0x7C,0x00, 10 | }; 11 | 12 | static uint8_t bitmaps_raw[] = { 13 | 0b00000100, 0b00000000, 14 | 0b00001000, 0b00000000, 15 | 0b01111111, 0b00000000, 16 | 0b11011111, 0b10000000, 17 | 0b10111111, 0b10000000, 18 | 0b11111111, 0b10000000, 19 | 0b11111111, 0b10000000, 20 | 0b01111111, 0b00000000, 21 | 0b00110110, 0b00000000, 22 | 23 | 0b00001000, 0b00000000, 24 | 0b01000001, 0b00000000, 25 | 0b00011100, 0b00000000, 26 | 0b00111110, 0b00000000, 27 | 0b10111110, 0b10000000, 28 | 0b00111110, 0b00000000, 29 | 0b00011100, 0b00000000, 30 | 0b01000001, 0b00000000, 31 | 0b00001000, 0b00000000, 32 | 33 | 0b00100000, 0b00000000, 34 | 0b01100000, 0b00000000, 35 | 0b11111111, 0b10000000, 36 | 0b01100000, 0b00000000, 37 | 0b00100010, 0b00000000, 38 | 0b00000011, 0b00000000, 39 | 0b11111111, 0b10000000, 40 | 0b00000011, 0b00000000, 41 | 0b00000010, 0b00000000, 42 | 43 | 0b01110111, 0b00000000, 44 | 0b10001000, 0b10000000, 45 | 0b00000000, 0b10000000, 46 | 0b01000000, 0b10000000, 47 | 0b11100000, 0b10000000, 48 | 0b01000001, 0b00000000, 49 | 0b00000010, 0b00000000, 50 | 0b00010100, 0b00000000, 51 | 0b00001000, 0b00000000, 52 | 53 | 0b00000100, 0b00000000, 54 | 0b01000000, 0b00000000, 55 | 0b00011001, 0b00000000, 56 | 0b00111000, 0b00000000, 57 | 0b00100110 ,0b00000000, 58 | 0b01111111, 0b00000000, 59 | 0b01111111, 0b00000000, 60 | 0b11110001, 0b10000000, 61 | 0b11111111, 0b10000000, 62 | 63 | 0b00111000, 0b00000000, 64 | 0b01000100, 0b00000000, 65 | 0b10000010, 0b00000000, 66 | 0b10000010, 0b00000000, 67 | 0b10000010, 0b00000000, 68 | 0b01000100, 0b00000000, 69 | 0b00111010, 0b00000000, 70 | 0b00000001, 0b00000000, 71 | 0b00000000, 0b10000000, 72 | 73 | 0b01111000, 0b00000000, 74 | 0b11111100, 0b00000000, 75 | 0b11001100, 0b00000000, 76 | 0b11110100, 0b00000000, 77 | 0b11111110, 0b00000000, 78 | 0b11111100, 0b10000000, 79 | 0b11111001, 0b00000000, 80 | 0b01111100, 0b10000000, 81 | 0b00110000, 0b00000000, 82 | 83 | 0b00111110, 0b00000000, 84 | 0b01000001, 0b00000000, 85 | 0b10001000, 0b10000000, 86 | 0b10001000, 0b10000000, 87 | 0b10001000, 0b10000000, 88 | 0b10000000, 0b10000000, 89 | 0b10001000, 0b10000000, 90 | 0b01000001, 0b00000000, 91 | 0b00111110, 0b00000000, 92 | 93 | }; 94 | -------------------------------------------------------------------------------- /cpu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #include 21 | #include "cpu.h" 22 | #include "hw.h" 23 | #include "hal.h" 24 | //#include "rom_new.h" 25 | #include "rom_12bit.h" 26 | 27 | #define CPU_SPEED_RATIO 0 28 | #define TICK_FREQUENCY 32768 // Hz 29 | 30 | #define TIMER_1HZ_PERIOD 32768 // in ticks 31 | #define TIMER_256HZ_PERIOD 128 // in ticks 32 | 33 | #define MASK_4B 0xF00 34 | #define MASK_6B 0xFC0 35 | #define MASK_7B 0xFE0 36 | #define MASK_8B 0xFF0 37 | #define MASK_10B 0xFFC 38 | #define MASK_12B 0xFFF 39 | 40 | #define PCS (pc & 0xFF) 41 | #define PCSL (pc & 0xF) 42 | #define PCSH ((pc >> 4) & 0xF) 43 | #define PCP ((pc >> 8) & 0xF) 44 | #define PCB ((pc >> 12) & 0x1) 45 | #define TO_PC(bank, page, step) ((step & 0xFF) | ((page & 0xF) << 8) | (bank & 0x1) << 12) 46 | #define NBP ((np >> 4) & 0x1) 47 | #define NPP (np & 0xF) 48 | #define TO_NP(bank, page) ((page & 0xF) | (bank & 0x1) << 4) 49 | #define XHL (x & 0xFF) 50 | #define XL1 (x & 0xF) 51 | #define XH1 ((x >> 4) & 0xF) 52 | #define XP ((x >> 8) & 0xF) 53 | #define YHL (y & 0xFF) 54 | #define YL1 (y & 0xF) 55 | #define YH1 ((y >> 4) & 0xF) 56 | #define YP ((y >> 8) & 0xF) 57 | #define M(n) get_memory(n) 58 | #define SET_M(n, v) set_memory(n, v) 59 | #define RQ(i) get_rq(i) 60 | #define SET_RQ(i, v) set_rq(i, v) 61 | #define SPL1 (sp & 0xF) 62 | #define SPH1 ((sp >> 4) & 0xF) 63 | 64 | #define FLAG_C (0x1 << 0) 65 | #define FLAG_Z (0x1 << 1) 66 | #define FLAG_D (0x1 << 2) 67 | #define FLAG_I (0x1 << 3) 68 | 69 | #define C !!(flags & FLAG_C) 70 | #define Z !!(flags & FLAG_Z) 71 | #define D !!(flags & FLAG_D) 72 | #define I !!(flags & FLAG_I) 73 | 74 | #define SET_C() {flags |= FLAG_C;} 75 | #define CLEAR_C() {flags &= ~FLAG_C;} 76 | #define SET_Z() {flags |= FLAG_Z;} 77 | #define CLEAR_Z() {flags &= ~FLAG_Z;} 78 | #define SET_D() {flags |= FLAG_D;} 79 | #define CLEAR_D() {flags &= ~FLAG_D;} 80 | #define SET_I() {flags |= FLAG_I;} 81 | #define CLEAR_I() {flags &= ~FLAG_I;} 82 | 83 | #define REG_CLK_INT_FACTOR_FLAGS 0xF00 84 | #define REG_SW_INT_FACTOR_FLAGS 0xF01 85 | #define REG_PROG_INT_FACTOR_FLAGS 0xF02 86 | #define REG_SERIAL_INT_FACTOR_FLAGS 0xF03 87 | #define REG_K00_K03_INT_FACTOR_FLAGS 0xF04 88 | #define REG_K10_K13_INT_FACTOR_FLAGS 0xF05 89 | #define REG_CLOCK_INT_MASKS 0xF10 90 | #define REG_SW_INT_MASKS 0xF11 91 | #define REG_PROG_INT_MASKS 0xF12 92 | #define REG_SERIAL_INT_MASKS 0xF13 93 | #define REG_K00_K03_INT_MASKS 0xF14 94 | #define REG_K10_K13_INT_MASKS 0xF15 95 | #define REG_PROG_TIMER_DATA_L 0xF24 96 | #define REG_PROG_TIMER_DATA_H 0xF25 97 | #define REG_PROG_TIMER_RELOAD_DATA_L 0xF26 98 | #define REG_PROG_TIMER_RELOAD_DATA_H 0xF27 99 | #define REG_K00_K03_INPUT_PORT 0xF40 100 | #define REG_K10_K13_INPUT_PORT 0xF42 101 | #define REG_K40_K43_BZ_OUTPUT_PORT 0xF54 102 | #define REG_CPU_OSC3_CTRL 0xF70 103 | #define REG_LCD_CTRL 0xF71 104 | #define REG_LCD_CONTRAST 0xF72 105 | #define REG_SVD_CTRL 0xF73 106 | #define REG_BUZZER_CTRL1 0xF74 107 | #define REG_BUZZER_CTRL2 0xF75 108 | #define REG_CLK_WD_TIMER_CTRL 0xF76 109 | #define REG_SW_TIMER_CTRL 0xF77 110 | #define REG_PROG_TIMER_CTRL 0xF78 111 | #define REG_PROG_TIMER_CLK_SEL 0xF79 112 | 113 | #define INPUT_PORT_NUM 2 114 | 115 | typedef struct { 116 | //char *log; 117 | u12_t code; 118 | u12_t mask; 119 | // u12_t shift_arg1; 120 | // u12_t mask_arg1; // != 0 only if there are two arguments 121 | u8_t cycles; 122 | // void (*cb0)(u8_t arg0, u8_t arg1); 123 | } op_t0; 124 | 125 | typedef struct { 126 | //char *log; 127 | // u12_t code; 128 | // u12_t mask; 129 | // u12_t shift_arg1; 130 | // u12_t mask_arg1; // != 0 only if there are two arguments 131 | // u8_t cycles; 132 | void (*cb1)(u8_t arg0, u8_t arg1); 133 | } op_t1; 134 | 135 | typedef struct { 136 | u4_t states; 137 | } input_port_t; 138 | 139 | /* Registers */ 140 | static u13_t pc, next_pc; 141 | static u12_t x, y; 142 | static u4_t a, b; 143 | static u5_t np; 144 | static u8_t sp; 145 | 146 | /* Flags */ 147 | static u4_t flags; 148 | 149 | //static const u12_t *g_program = NULL; 150 | static u4_t memory[MEMORY_SIZE]; 151 | //static u4_t io_memory[MEM_IO_SIZE]; 152 | 153 | static input_port_t inputs[INPUT_PORT_NUM] = {{0}}; 154 | 155 | //static u8_t maxNumber = 0; 156 | 157 | /* Interrupts (in priority order) */ 158 | static interrupt_t interrupts[INT_SLOT_NUM] = { 159 | {0x0, 0x0, 0, 0x0C}, // Prog timer 160 | {0x0, 0x0, 0, 0x0A}, // Serial interface 161 | {0x0, 0x0, 0, 0x08}, // Input (K10-K13) 162 | {0x0, 0x0, 0, 0x06}, // Input (K00-K03) 163 | {0x0, 0x0, 0, 0x04}, // Stopwatch timer 164 | {0x0, 0x0, 0, 0x02}, // Clock timer 165 | }; 166 | 167 | //static breakpoint_t *g_breakpoints = NULL; 168 | 169 | static u32_t call_depth = 0; 170 | 171 | static u32_t clk_timer_timestamp = 0; // in ticks 172 | static u32_t prog_timer_timestamp = 0; // in ticks 173 | static bool_t prog_timer_enabled = 0; 174 | static u8_t prog_timer_data = 0; 175 | static u8_t prog_timer_rld = 0; 176 | 177 | static u32_t tick_counter = 0; 178 | static u32_t ts_freq; 179 | //static u8_t speed_ratio = 0; 180 | static timestamp_t ref_ts; 181 | 182 | /* 183 | static state_t cpu_state = { 184 | .pc = &pc, 185 | .x = &x, 186 | .y = &y, 187 | .a = &a, 188 | .b = &b, 189 | .np = &np, 190 | .sp = &sp, 191 | .flags = &flags, 192 | 193 | .tick_counter = &tick_counter, 194 | .clk_timer_timestamp = &clk_timer_timestamp, 195 | .prog_timer_timestamp = &prog_timer_timestamp, 196 | .prog_timer_enabled = &prog_timer_enabled, 197 | .prog_timer_data = &prog_timer_data, 198 | .prog_timer_rld = &prog_timer_rld, 199 | 200 | .call_depth = &call_depth, 201 | 202 | .interrupts = interrupts, 203 | 204 | .memory = memory, 205 | }; */ 206 | 207 | 208 | void cpu_add_bp(breakpoint_t **list, u13_t addr) 209 | { 210 | /* breakpoint_t *bp; 211 | 212 | bp = (breakpoint_t *) g_hal->malloc(sizeof(breakpoint_t)); 213 | if (!bp) { 214 | g_hal->log(LOG_ERROR, "Cannot allocate memory for breakpoint 0x%04X!\n", addr); 215 | return; 216 | } 217 | 218 | bp->addr = addr; 219 | 220 | if (*list != NULL) { 221 | bp->next = *list; 222 | } else { 223 | bp->next = NULL; 224 | } 225 | 226 | *list = bp; */ 227 | } 228 | 229 | void cpu_free_bp(breakpoint_t **list) 230 | { 231 | /* breakpoint_t *bp = *list, *tmp; 232 | while (bp != NULL) { 233 | tmp = bp->next; 234 | g_hal->free(bp); 235 | bp = tmp; 236 | } 237 | *list = NULL; */ 238 | } 239 | /* 240 | void cpu_set_speed(u8_t speed) 241 | { 242 | speed_ratio = speed; 243 | }*/ 244 | 245 | 246 | void cpu_get_state(cpu_state_t *cpustate) 247 | { 248 | cpustate->pc = pc; 249 | cpustate->x = x; 250 | cpustate->y = y; 251 | cpustate->a = a; 252 | cpustate->b = b; 253 | cpustate->np = np; 254 | cpustate->sp = sp; 255 | 256 | cpustate->flags = flags; 257 | cpustate->tick_counter = tick_counter; 258 | cpustate->clk_timer_timestamp = clk_timer_timestamp; 259 | cpustate->prog_timer_timestamp = prog_timer_timestamp; 260 | cpustate->prog_timer_enabled = prog_timer_enabled; 261 | cpustate->prog_timer_data = prog_timer_data; 262 | cpustate->prog_timer_rld = prog_timer_rld; 263 | cpustate->call_depth = call_depth; 264 | cpustate->memory = (u4_t *)memory; 265 | uint8_t i; 266 | for(i=0;i<6;i++) { 267 | cpustate->interrupts[i].factor_flag_reg = interrupts[i].factor_flag_reg; 268 | cpustate->interrupts[i].mask_reg = interrupts[i].mask_reg; 269 | cpustate->interrupts[i].triggered = interrupts[i].triggered; 270 | cpustate->interrupts[i].vector = interrupts[i].vector; 271 | } 272 | } 273 | 274 | void cpu_set_state(cpu_state_t *cpustate) 275 | { 276 | pc = cpustate->pc; 277 | x = cpustate->x; 278 | y = cpustate->y; 279 | a = cpustate->a; 280 | b = cpustate->b; 281 | np = cpustate->np; 282 | sp = cpustate->sp; 283 | flags = cpustate->flags; 284 | tick_counter = cpustate->tick_counter; 285 | clk_timer_timestamp = cpustate->clk_timer_timestamp; 286 | prog_timer_timestamp = cpustate->prog_timer_timestamp; 287 | prog_timer_enabled = cpustate->prog_timer_enabled; 288 | prog_timer_data = cpustate->prog_timer_data; 289 | prog_timer_rld = cpustate->prog_timer_rld; 290 | call_depth = cpustate->call_depth; 291 | //memory = (u4_t *)cpustate->memory; 292 | uint8_t i; 293 | for(i=0;i<6;i++) { 294 | interrupts[i].factor_flag_reg = cpustate->interrupts[i].factor_flag_reg; 295 | interrupts[i].mask_reg = cpustate->interrupts[i].mask_reg; 296 | interrupts[i].triggered = cpustate->interrupts[i].triggered; 297 | interrupts[i].vector = cpustate->interrupts[i].vector; 298 | } 299 | } 300 | 301 | u32_t cpu_get_depth(void) 302 | { 303 | return call_depth; 304 | } 305 | 306 | static void generate_interrupt(int_slot_t slot, u8_t bit) 307 | { 308 | /* Set the factor flag no matter what */ 309 | interrupts[slot].factor_flag_reg = interrupts[slot].factor_flag_reg | (0x1 << bit); 310 | 311 | /* Trigger the INT only if not masked */ 312 | if (interrupts[slot].mask_reg & (0x1 << bit)) { 313 | interrupts[slot].triggered = 1; 314 | } 315 | } 316 | 317 | void cpu_set_input_pin(pin_t pin, pin_state_t state) 318 | { 319 | /* Set the I/O */ 320 | inputs[pin & 0x4].states = (inputs[pin & 0x4].states & ~(0x1 << (pin & 0x3))) | (state << (pin & 0x3)); 321 | 322 | /* Trigger the interrupt (TODO: handle relation register) */ 323 | if (state == PIN_STATE_LOW) { 324 | switch ((pin & 0x4) >> 2) { 325 | case 0: 326 | generate_interrupt(INT_K00_K03_SLOT, pin & 0x3); 327 | break; 328 | 329 | case 1: 330 | generate_interrupt(INT_K10_K13_SLOT, pin & 0x3); 331 | break; 332 | } 333 | } 334 | } 335 | 336 | void cpu_sync_ref_timestamp(void) 337 | { 338 | ref_ts = g_hal->get_timestamp(); 339 | } 340 | 341 | static u4_t get_io(u12_t n) 342 | { 343 | u4_t tmp; 344 | 345 | switch (n) { 346 | case REG_CLK_INT_FACTOR_FLAGS: 347 | /* Interrupt factor flags (clock timer) */ 348 | tmp = interrupts[INT_CLOCK_TIMER_SLOT].factor_flag_reg; 349 | interrupts[INT_CLOCK_TIMER_SLOT].factor_flag_reg = 0; 350 | return tmp; 351 | 352 | case REG_SW_INT_FACTOR_FLAGS: 353 | /* Interrupt factor flags (stopwatch) */ 354 | tmp = interrupts[INT_STOPWATCH_SLOT].factor_flag_reg; 355 | interrupts[INT_STOPWATCH_SLOT].factor_flag_reg = 0; 356 | return tmp; 357 | 358 | case REG_PROG_INT_FACTOR_FLAGS: 359 | /* Interrupt factor flags (prog timer) */ 360 | tmp = interrupts[INT_PROG_TIMER_SLOT].factor_flag_reg; 361 | interrupts[INT_PROG_TIMER_SLOT].factor_flag_reg = 0; 362 | return tmp; 363 | 364 | case REG_SERIAL_INT_FACTOR_FLAGS: 365 | /* Interrupt factor flags (serial) */ 366 | tmp = interrupts[INT_SERIAL_SLOT].factor_flag_reg; 367 | interrupts[INT_SERIAL_SLOT].factor_flag_reg = 0; 368 | return tmp; 369 | 370 | case REG_K00_K03_INT_FACTOR_FLAGS: 371 | /* Interrupt factor flags (K00-K03) */ 372 | tmp = interrupts[INT_K00_K03_SLOT].factor_flag_reg; 373 | interrupts[INT_K00_K03_SLOT].factor_flag_reg = 0; 374 | return tmp; 375 | 376 | case REG_K10_K13_INT_FACTOR_FLAGS: 377 | /* Interrupt factor flags (K10-K13) */ 378 | tmp = interrupts[INT_K10_K13_SLOT].factor_flag_reg; 379 | interrupts[INT_K10_K13_SLOT].factor_flag_reg = 0; 380 | return tmp; 381 | 382 | case REG_CLOCK_INT_MASKS: 383 | /* Clock timer interrupt masks */ 384 | return interrupts[INT_CLOCK_TIMER_SLOT].mask_reg; 385 | 386 | case REG_SW_INT_MASKS: 387 | /* Stopwatch interrupt masks */ 388 | return interrupts[INT_STOPWATCH_SLOT].mask_reg & 0x3; 389 | 390 | case REG_PROG_INT_MASKS: 391 | /* Prog timer interrupt masks */ 392 | return interrupts[INT_PROG_TIMER_SLOT].mask_reg & 0x1; 393 | 394 | case REG_SERIAL_INT_MASKS: 395 | /* Serial interface interrupt masks */ 396 | return interrupts[INT_SERIAL_SLOT].mask_reg & 0x1; 397 | 398 | case REG_K00_K03_INT_MASKS: 399 | /* Input (K00-K03) interrupt masks */ 400 | return interrupts[INT_K00_K03_SLOT].mask_reg; 401 | 402 | case REG_K10_K13_INT_MASKS: 403 | /* Input (K10-K13) interrupt masks */ 404 | return interrupts[INT_K10_K13_SLOT].mask_reg; 405 | 406 | case REG_PROG_TIMER_DATA_L: 407 | /* Prog timer data (low) */ 408 | return prog_timer_data & 0xF; 409 | 410 | case REG_PROG_TIMER_DATA_H: 411 | /* Prog timer data (high) */ 412 | return (prog_timer_data >> 4) & 0xF; 413 | 414 | case REG_PROG_TIMER_RELOAD_DATA_L: 415 | /* Prog timer reload data (low) */ 416 | return prog_timer_rld & 0xF; 417 | 418 | case REG_PROG_TIMER_RELOAD_DATA_H: 419 | /* Prog timer reload data (high) */ 420 | return (prog_timer_rld >> 4) & 0xF; 421 | 422 | case REG_K00_K03_INPUT_PORT: 423 | /* Input port (K00-K03) */ 424 | return inputs[0].states; 425 | 426 | case REG_K10_K13_INPUT_PORT: 427 | /* Input port (K10-K13) */ 428 | return inputs[1].states; 429 | 430 | case REG_K40_K43_BZ_OUTPUT_PORT: 431 | /* Output port (R40-R43) */ 432 | //return io_memory[n - MEM_IO_ADDR_OFS]; 433 | return 0xf; 434 | case REG_CPU_OSC3_CTRL: 435 | /* CPU/OSC3 clocks switch, CPU voltage switch */ 436 | //return io_memory[n - MEM_IO_ADDR_OFS]; 437 | return 0; 438 | case REG_LCD_CTRL: 439 | /* LCD control */ 440 | //return io_memory[n - MEM_IO_ADDR_OFS]; 441 | return 0x8; 442 | case REG_LCD_CONTRAST: 443 | /* LCD contrast */ 444 | break; 445 | 446 | case REG_SVD_CTRL: 447 | /* SVD */ 448 | //return io_memory[n - MEM_IO_ADDR_OFS] & 0x7; // Voltage always OK 449 | return 0; 450 | case REG_BUZZER_CTRL1: 451 | /* Buzzer config 1 */ 452 | //return memory[n - MEM_IO_ADDR_OFS]; 453 | return 0; 454 | case REG_BUZZER_CTRL2: 455 | /* Buzzer config 2 */ 456 | //return io_memory[n - MEM_IO_ADDR_OFS] & 0x3; // Buzzer ready 457 | return 0; 458 | case REG_CLK_WD_TIMER_CTRL: 459 | /* Clock/Watchdog timer reset */ 460 | break; 461 | 462 | case REG_SW_TIMER_CTRL: 463 | /* Stopwatch stop/run/reset */ 464 | break; 465 | 466 | case REG_PROG_TIMER_CTRL: 467 | /* Prog timer stop/run/reset */ 468 | return !!prog_timer_enabled; 469 | 470 | case REG_PROG_TIMER_CLK_SEL: 471 | /* Prog timer clock selection */ 472 | break; 473 | 474 | default: 475 | break; 476 | //g_hal->log(LOG_ERROR, "Read from unimplemented I/O 0x%03X - PC = 0x%04X\n", n, pc); 477 | } 478 | 479 | return 0; 480 | } 481 | 482 | static void set_io(u12_t n, u4_t v) 483 | { 484 | switch (n) { 485 | case REG_CLOCK_INT_MASKS: 486 | /* Clock timer interrupt masks */ 487 | /* Assume 1Hz timer INT enabled (0x8) */ 488 | interrupts[INT_CLOCK_TIMER_SLOT].mask_reg = v; 489 | break; 490 | 491 | case REG_SW_INT_MASKS: 492 | /* Stopwatch interrupt masks */ 493 | /* Assume all INT disabled */ 494 | interrupts[INT_STOPWATCH_SLOT].mask_reg = v; 495 | break; 496 | 497 | case REG_PROG_INT_MASKS: 498 | /* Prog timer interrupt masks */ 499 | /* Assume Prog timer INT enabled (0x1) */ 500 | interrupts[INT_PROG_TIMER_SLOT].mask_reg = v; 501 | break; 502 | 503 | case REG_SERIAL_INT_MASKS: 504 | /* Serial interface interrupt masks */ 505 | /* Assume all INT disabled */ 506 | interrupts[INT_K10_K13_SLOT].mask_reg = v; 507 | break; 508 | 509 | case REG_K00_K03_INT_MASKS: 510 | /* Input (K00-K03) interrupt masks */ 511 | /* Assume all INT disabled */ 512 | interrupts[INT_SERIAL_SLOT].mask_reg = v; 513 | break; 514 | 515 | case REG_K10_K13_INT_MASKS: 516 | /* Input (K10-K13) interrupt masks */ 517 | /* Assume all INT disabled */ 518 | interrupts[INT_K10_K13_SLOT].mask_reg = v; 519 | break; 520 | 521 | case REG_PROG_TIMER_RELOAD_DATA_L: 522 | /* Prog timer reload data (low) */ 523 | prog_timer_rld = v | (prog_timer_rld & 0xF0); 524 | break; 525 | 526 | case REG_PROG_TIMER_RELOAD_DATA_H: 527 | /* Prog timer reload data (high) */ 528 | prog_timer_rld = (prog_timer_rld & 0xF) | (v << 4); 529 | break; 530 | 531 | case REG_K00_K03_INPUT_PORT: 532 | /* Input port (K00-K03) */ 533 | /* Write not allowed */ 534 | break; 535 | 536 | case REG_K40_K43_BZ_OUTPUT_PORT: 537 | /* Output port (R40-R43) */ 538 | //g_hal->log(LOG_INFO, "Output/Buzzer: 0x%X\n", v); 539 | hw_enable_buzzer(!(v & 0x8)); 540 | break; 541 | 542 | case REG_CPU_OSC3_CTRL: 543 | /* CPU/OSC3 clocks switch, CPU voltage switch */ 544 | /* Assume 32,768 OSC1 selected, OSC3 off, battery >= 3,1V (0x1) */ 545 | break; 546 | 547 | case REG_LCD_CTRL: 548 | /* LCD control */ 549 | break; 550 | 551 | case REG_LCD_CONTRAST: 552 | /* LCD contrast */ 553 | /* Assume medium contrast (0x8) */ 554 | break; 555 | 556 | case REG_SVD_CTRL: 557 | /* SVD */ 558 | /* Assume battery voltage always OK (0x6) */ 559 | break; 560 | 561 | case REG_BUZZER_CTRL1: 562 | /* Buzzer config 1 */ 563 | hw_set_buzzer_freq(v & 0x7); 564 | break; 565 | 566 | case REG_BUZZER_CTRL2: 567 | /* Buzzer config 2 */ 568 | break; 569 | 570 | case REG_CLK_WD_TIMER_CTRL: 571 | /* Clock/Watchdog timer reset */ 572 | /* Ignore watchdog */ 573 | break; 574 | 575 | case REG_SW_TIMER_CTRL: 576 | /* Stopwatch stop/run/reset */ 577 | break; 578 | 579 | case REG_PROG_TIMER_CTRL: 580 | /* Prog timer stop/run/reset */ 581 | if (v & 0x2) { 582 | prog_timer_data = prog_timer_rld; 583 | } 584 | 585 | if ((v & 0x1) && !prog_timer_enabled) { 586 | prog_timer_timestamp = tick_counter; 587 | } 588 | 589 | prog_timer_enabled = v & 0x1; 590 | break; 591 | 592 | case REG_PROG_TIMER_CLK_SEL: 593 | /* Prog timer clock selection */ 594 | /* Assume 256Hz, output disabled */ 595 | break; 596 | 597 | default: 598 | break; 599 | //g_hal->log(LOG_ERROR, "Write 0x%X to unimplemented I/O 0x%03X - PC = 0x%04X\n", v, n, pc); 600 | } 601 | } 602 | 603 | static void set_lcd(u12_t n, u4_t v) 604 | { 605 | u8_t i; 606 | u8_t seg, com0; 607 | 608 | seg = ((n & 0x7F) >> 1); 609 | com0 = (((n & 0x80) >> 7) * 8 + (n & 0x1) * 4); 610 | 611 | for (i = 0; i < 4; i++) { 612 | hw_set_lcd_pin(seg, com0 + i, (v >> i) & 0x1); 613 | } 614 | } 615 | 616 | /* 617 | #define MEMORY_SIZE 1280 // 4096 x 4 bits (640 x 4 bits of RAM) 618 | 619 | #define MEM_RAM_ADDR 0x000 620 | #define MEM_RAM_SIZE 0x280 // 640 621 | #define MEM_DISPLAY1_ADDR 0xE00 // 3584 0x280 622 | #define MEM_DISPLAY1_ADDR_OFS 0xB80 623 | #define MEM_DISPLAY1_SIZE 0x050 // 80 624 | #define MEM_DISPLAY2_ADDR 0xE80 // 3712 0x2D0 625 | #define MEM_DISPLAY2_ADDR_OFS 0xBB0 626 | #define MEM_DISPLAY2_SIZE 0x050 // 80 627 | #define MEM_IO_ADDR 0xF00 // 3840 0x320 628 | #define MEM_IO_ADDR_OFS 0xBE0 629 | #define MEM_IO_SIZE 0x080 // 128 0x3a0 630 | 631 | */ 632 | /* 633 | u8_t cpu_get_max_number() { 634 | return maxNumber; 635 | } 636 | */ 637 | static u4_t get_memory(u12_t n) 638 | { 639 | u4_t res = 0; 640 | 641 | 642 | if (n < MEM_RAM_SIZE) { 643 | /* RAM */ 644 | //g_hal->log(LOG_MEMORY, "RAM - "); 645 | //if (n > max_memory_addr_access) max_memory_addr_access = n; 646 | if ((n & 0x1)==0) { 647 | res = memory[n>>1] >> 4; 648 | } else { 649 | res = memory[n>>1] & 0b00001111; 650 | } 651 | 652 | } else if (n >= MEM_DISPLAY1_ADDR && n < (MEM_DISPLAY1_ADDR + MEM_DISPLAY1_SIZE)) { 653 | /* Display Memory 1 */ 654 | //g_hal->log(LOG_MEMORY, "Display Memory 1 - "); 655 | //res = memory[n - MEM_DISPLAY1_ADDR_OFS]; 656 | res = 0; 657 | 658 | } else if (n >= MEM_DISPLAY2_ADDR && n < (MEM_DISPLAY2_ADDR + MEM_DISPLAY2_SIZE)) { 659 | /* Display Memory 2 */ 660 | //g_hal->log(LOG_MEMORY, "Display Memory 2 - "); 661 | //res = memory[n - MEM_DISPLAY2_ADDR_OFS]; 662 | res = 0; 663 | } else if (n >= MEM_IO_ADDR && n < (MEM_IO_ADDR + MEM_IO_SIZE)) { 664 | /* I/O Memory */ 665 | //g_hal->log(LOG_MEMORY, "I/O - "); 666 | res = get_io(n); 667 | } else { 668 | //g_hal->log(LOG_ERROR, "Read from invalid memory address 0x%03X - PC = 0x%04X\n", n, pc); 669 | return 0; 670 | } 671 | 672 | //g_hal->log(LOG_MEMORY, "Read 0x%X - Address 0x%03X - PC = 0x%04X\n", res, n, pc); 673 | 674 | return res; 675 | } 676 | 677 | static void set_memory(u12_t n, u4_t v) 678 | { 679 | if (n < MEM_RAM_SIZE) { 680 | /* RAM */ 681 | //g_hal->log(LOG_MEMORY, "RAM - "); 682 | if ((n & 0x1)==0) { 683 | memory[n>>1] = (memory[n>>1] & 0x0F) | (v << 4); 684 | } else { 685 | memory[n>>1] = (memory[n>>1] & 0xF0) | v; 686 | } 687 | //memory[n] = v; 688 | } else if (n >= MEM_DISPLAY1_ADDR && n < (MEM_DISPLAY1_ADDR + MEM_DISPLAY1_SIZE)) { 689 | /* Display Memory 1 */ 690 | set_lcd(n, v); 691 | //memory[n - MEM_DISPLAY1_ADDR_OFS] = v; 692 | //g_hal->log(LOG_MEMORY, "Display Memory 1 - "); 693 | } else if (n >= MEM_DISPLAY2_ADDR && n < (MEM_DISPLAY2_ADDR + MEM_DISPLAY2_SIZE)) { 694 | /* Display Memory 2 */ 695 | set_lcd(n, v); 696 | //memory[n - MEM_DISPLAY2_ADDR_OFS] = v; 697 | //g_hal->log(LOG_MEMORY, "Display Memory 2 - "); 698 | } else if (n >= MEM_IO_ADDR && n < (MEM_IO_ADDR + MEM_IO_SIZE)) { 699 | /* I/O Memory */ 700 | set_io(n, v); 701 | //g_hal->log(LOG_MEMORY, "I/O - "); 702 | } else { 703 | //g_hal->log(LOG_ERROR, "Write 0x%X to invalid memory address 0x%03X - PC = 0x%04X\n", v, n, pc); 704 | return; 705 | } 706 | //g_hal->log(LOG_MEMORY, "Write 0x%X - Address 0x%03X - PC = 0x%04X\n", v, n, pc); 707 | } 708 | /* 709 | void cpu_refresh_hw(void) 710 | { 711 | static const struct range { 712 | u12_t addr; 713 | u12_t size; 714 | } refresh_locs[] = { 715 | { MEM_DISPLAY1_ADDR, MEM_DISPLAY1_SIZE }, // Display Memory 1 716 | { MEM_DISPLAY2_ADDR, MEM_DISPLAY2_SIZE }, // Display Memory 2 717 | { REG_BUZZER_CTRL1, 1 }, // Buzzer frequency 718 | { REG_K40_K43_BZ_OUTPUT_PORT, 1 }, // Buzzer enabled 719 | 720 | { 0, 0 }, // end of list 721 | }; 722 | 723 | for (int i = 0; refresh_locs[i].size != 0; i++) { 724 | for (u12_t n = refresh_locs[i].addr; n < (refresh_locs[i].addr + refresh_locs[i].size); n++) { 725 | set_memory(n, memory[n]); 726 | } 727 | } 728 | }*/ 729 | 730 | static u4_t get_rq(u12_t rq) 731 | { 732 | switch (rq & 0x3) { 733 | case 0x0: return a; 734 | case 0x1: return b; 735 | case 0x2: return M(x); 736 | case 0x3: return M(y); 737 | } 738 | return 0; 739 | } 740 | 741 | static void set_rq(u12_t rq, u4_t v) 742 | { 743 | switch (rq & 0x3) { 744 | case 0x0: a = v; break; 745 | case 0x1: b = v; break; 746 | case 0x2: SET_M(x, v); break; 747 | case 0x3: SET_M(y, v); break; 748 | } 749 | } 750 | 751 | /* Instructions */ 752 | static void op_pset_cb(u8_t arg0, u8_t arg1) 753 | { 754 | np = arg0; 755 | } 756 | 757 | static void op_jp_cb(u8_t arg0, u8_t arg1) 758 | { 759 | next_pc = arg0 | (np << 8); 760 | } 761 | 762 | static void op_jp_c_cb(u8_t arg0, u8_t arg1) 763 | { 764 | if (flags & FLAG_C) { 765 | next_pc = arg0 | (np << 8); 766 | } 767 | } 768 | 769 | static void op_jp_nc_cb(u8_t arg0, u8_t arg1) 770 | { 771 | if (!(flags & FLAG_C)) { 772 | next_pc = arg0 | (np << 8); 773 | } 774 | } 775 | 776 | static void op_jp_z_cb(u8_t arg0, u8_t arg1) 777 | { 778 | if (flags & FLAG_Z) { 779 | next_pc = arg0 | (np << 8); 780 | } 781 | } 782 | 783 | static void op_jp_nz_cb(u8_t arg0, u8_t arg1) 784 | { 785 | if (!(flags & FLAG_Z)) { 786 | next_pc = arg0 | (np << 8); 787 | } 788 | } 789 | 790 | static void op_jpba_cb(u8_t arg0, u8_t arg1) 791 | { 792 | next_pc = a | (b << 4) | (np << 8); 793 | } 794 | 795 | static void op_call_cb(u8_t arg0, u8_t arg1) 796 | { 797 | pc = (pc + 1) & 0x1FFF; // This does not actually change the PC register 798 | SET_M(sp - 1, PCP); 799 | SET_M(sp - 2, PCSH); 800 | SET_M(sp - 3, PCSL); 801 | sp = (sp - 3) & 0xFF; 802 | next_pc = TO_PC(PCB, NPP, arg0); 803 | call_depth++; 804 | } 805 | 806 | static void op_calz_cb(u8_t arg0, u8_t arg1) 807 | { 808 | pc = (pc + 1) & 0x1FFF; // This does not actually change the PC register 809 | SET_M(sp - 1, PCP); 810 | SET_M(sp - 2, PCSH); 811 | SET_M(sp - 3, PCSL); 812 | sp = (sp - 3) & 0xFF; 813 | next_pc = TO_PC(PCB, 0, arg0); 814 | call_depth++; 815 | } 816 | 817 | static void op_ret_cb(u8_t arg0, u8_t arg1) 818 | { 819 | next_pc = M(sp) | (M(sp + 1) << 4) | (M(sp + 2) << 8) | (PCB << 12); 820 | sp = (sp + 3) & 0xFF; 821 | call_depth--; 822 | } 823 | 824 | static void op_rets_cb(u8_t arg0, u8_t arg1) 825 | { 826 | next_pc = M(sp) | (M(sp + 1) << 4) | (M(sp + 2) << 8) | (PCB << 12); 827 | sp = (sp + 3) & 0xFF; 828 | next_pc = (pc + 1) & 0x1FFF; 829 | call_depth--; 830 | } 831 | 832 | static void op_retd_cb(u8_t arg0, u8_t arg1) 833 | { 834 | next_pc = M(sp) | (M(sp + 1) << 4) | (M(sp + 2) << 8) | (PCB << 12); 835 | sp = (sp + 3) & 0xFF; 836 | SET_M(x, arg0 & 0xF); 837 | SET_M(x + 1, (arg0 >> 4) & 0xF); 838 | x = (x + 2) & 0xFFF; 839 | call_depth--; 840 | } 841 | 842 | static void op_nop5_cb(u8_t arg0, u8_t arg1) 843 | { 844 | } 845 | 846 | static void op_nop7_cb(u8_t arg0, u8_t arg1) 847 | { 848 | } 849 | 850 | static void op_halt_cb(u8_t arg0, u8_t arg1) 851 | { 852 | g_hal->halt(); 853 | } 854 | 855 | static void op_inc_x_cb(u8_t arg0, u8_t arg1) 856 | { 857 | x = (x + 1) & 0xFFF; 858 | } 859 | 860 | static void op_inc_y_cb(u8_t arg0, u8_t arg1) 861 | { 862 | y = (y + 1) & 0xFFF; 863 | } 864 | 865 | static void op_ld_x_cb(u8_t arg0, u8_t arg1) 866 | { 867 | x = arg0 | (XP << 8); 868 | } 869 | 870 | static void op_ld_y_cb(u8_t arg0, u8_t arg1) 871 | { 872 | y = arg0 | (YP << 8); 873 | } 874 | 875 | static void op_ld_xp_r_cb(u8_t arg0, u8_t arg1) 876 | { 877 | x = XHL | (RQ(arg0) << 8); 878 | } 879 | 880 | static void op_ld_xh_r_cb(u8_t arg0, u8_t arg1) 881 | { 882 | x = XL1 | (RQ(arg0) << 4) | (XP << 8); 883 | } 884 | 885 | static void op_ld_xl_r_cb(u8_t arg0, u8_t arg1) 886 | { 887 | x = RQ(arg0) | (XH1 << 4) | (XP << 8); 888 | } 889 | 890 | static void op_ld_yp_r_cb(u8_t arg0, u8_t arg1) 891 | { 892 | y = YHL | (RQ(arg0) << 8); 893 | } 894 | 895 | static void op_ld_yh_r_cb(u8_t arg0, u8_t arg1) 896 | { 897 | y = YL1 | (RQ(arg0) << 4) | (YP << 8); 898 | } 899 | 900 | static void op_ld_yl_r_cb(u8_t arg0, u8_t arg1) 901 | { 902 | y = RQ(arg0) | (YH1 << 4) | (YP << 8); 903 | } 904 | 905 | static void op_ld_r_xp_cb(u8_t arg0, u8_t arg1) 906 | { 907 | SET_RQ(arg0, XP); 908 | } 909 | 910 | static void op_ld_r_xh_cb(u8_t arg0, u8_t arg1) 911 | { 912 | SET_RQ(arg0, XH1); 913 | } 914 | 915 | static void op_ld_r_xl_cb(u8_t arg0, u8_t arg1) 916 | { 917 | SET_RQ(arg0, XL1); 918 | } 919 | 920 | static void op_ld_r_yp_cb(u8_t arg0, u8_t arg1) 921 | { 922 | SET_RQ(arg0, YP); 923 | } 924 | 925 | static void op_ld_r_yh_cb(u8_t arg0, u8_t arg1) 926 | { 927 | SET_RQ(arg0, YH1); 928 | } 929 | 930 | static void op_ld_r_yl_cb(u8_t arg0, u8_t arg1) 931 | { 932 | SET_RQ(arg0, YL1); 933 | } 934 | 935 | static void op_adc_xh_cb(u8_t arg0, u8_t arg1) 936 | { 937 | u8_t tmp; 938 | 939 | tmp = XH1 + arg0 + C; 940 | x = XL1 | ((tmp & 0xF) << 4)| (XP << 8); 941 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 942 | if (!(tmp & 0xF)) { SET_Z(); } else { CLEAR_Z(); } 943 | } 944 | 945 | static void op_adc_xl_cb(u8_t arg0, u8_t arg1) 946 | { 947 | u8_t tmp; 948 | 949 | tmp = XL1 + arg0 + C; 950 | x = (tmp & 0xF) | (XH1 << 4) | (XP << 8); 951 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 952 | if (!(tmp & 0xF)) { SET_Z(); } else { CLEAR_Z(); } 953 | } 954 | 955 | static void op_adc_yh_cb(u8_t arg0, u8_t arg1) 956 | { 957 | u8_t tmp; 958 | 959 | tmp = YH1 + arg0 + C; 960 | y = YL1 | ((tmp & 0xF) << 4)| (YP << 8); 961 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 962 | if (!(tmp & 0xF)) { SET_Z(); } else { CLEAR_Z(); } 963 | } 964 | 965 | static void op_adc_yl_cb(u8_t arg0, u8_t arg1) 966 | { 967 | u8_t tmp; 968 | 969 | tmp = YL1 + arg0 + C; 970 | y = (tmp & 0xF) | (YH1 << 4) | (YP << 8); 971 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 972 | if (!(tmp & 0xF)) { SET_Z(); } else { CLEAR_Z(); } 973 | } 974 | 975 | static void op_cp_xh_cb(u8_t arg0, u8_t arg1) 976 | { 977 | if (XH1 < arg0) { SET_C(); } else { CLEAR_C(); } 978 | if (XH1 == arg0) { SET_Z(); } else { CLEAR_Z(); } 979 | } 980 | 981 | static void op_cp_xl_cb(u8_t arg0, u8_t arg1) 982 | { 983 | if (XL1 < arg0) { SET_C(); } else { CLEAR_C(); } 984 | if (XL1 == arg0) { SET_Z(); } else { CLEAR_Z(); } 985 | } 986 | 987 | static void op_cp_yh_cb(u8_t arg0, u8_t arg1) 988 | { 989 | if (YH1 < arg0) { SET_C(); } else { CLEAR_C(); } 990 | if (YH1 == arg0) { SET_Z(); } else { CLEAR_Z(); } 991 | } 992 | 993 | static void op_cp_yl_cb(u8_t arg0, u8_t arg1) 994 | { 995 | if (YL1 < arg0) { SET_C(); } else { CLEAR_C(); } 996 | if (YL1 == arg0) { SET_Z(); } else { CLEAR_Z(); } 997 | } 998 | 999 | static void op_ld_r_i_cb(u8_t arg0, u8_t arg1) 1000 | { 1001 | SET_RQ(arg0, arg1); 1002 | } 1003 | 1004 | static void op_ld_r_q_cb(u8_t arg0, u8_t arg1) 1005 | { 1006 | SET_RQ(arg0, RQ(arg1)); 1007 | } 1008 | 1009 | static void op_ld_a_mn_cb(u8_t arg0, u8_t arg1) 1010 | { 1011 | a = M(arg0); 1012 | } 1013 | 1014 | static void op_ld_b_mn_cb(u8_t arg0, u8_t arg1) 1015 | { 1016 | b = M(arg0); 1017 | } 1018 | 1019 | static void op_ld_mn_a_cb(u8_t arg0, u8_t arg1) 1020 | { 1021 | SET_M(arg0, a); 1022 | } 1023 | 1024 | static void op_ld_mn_b_cb(u8_t arg0, u8_t arg1) 1025 | { 1026 | SET_M(arg0, b); 1027 | } 1028 | 1029 | static void op_ldpx_mx_cb(u8_t arg0, u8_t arg1) 1030 | { 1031 | SET_M(x, arg0); 1032 | x = (x + 1) & 0xFFF; 1033 | } 1034 | 1035 | static void op_ldpx_r_cb(u8_t arg0, u8_t arg1) 1036 | { 1037 | SET_RQ(arg0, RQ(arg1)); 1038 | x = (x + 1) & 0xFFF; 1039 | } 1040 | 1041 | static void op_ldpy_my_cb(u8_t arg0, u8_t arg1) 1042 | { 1043 | SET_M(y, arg0); 1044 | y = (y + 1) & 0xFFF; 1045 | } 1046 | 1047 | static void op_ldpy_r_cb(u8_t arg0, u8_t arg1) 1048 | { 1049 | SET_RQ(arg0, RQ(arg1)); 1050 | y = (y + 1) & 0xFFF; 1051 | } 1052 | 1053 | static void op_lbpx_cb(u8_t arg0, u8_t arg1) 1054 | { 1055 | SET_M(x, arg0 & 0xF); 1056 | SET_M(x + 1, (arg0 >> 4) & 0xF); 1057 | x = (x + 2) & 0xFFF; 1058 | } 1059 | 1060 | static void op_set_cb(u8_t arg0, u8_t arg1) 1061 | { 1062 | flags |= arg0; 1063 | } 1064 | 1065 | static void op_rst_cb(u8_t arg0, u8_t arg1) 1066 | { 1067 | flags &= arg0; 1068 | } 1069 | 1070 | static void op_scf_cb(u8_t arg0, u8_t arg1) 1071 | { 1072 | SET_C(); 1073 | } 1074 | 1075 | static void op_rcf_cb(u8_t arg0, u8_t arg1) 1076 | { 1077 | CLEAR_C(); 1078 | } 1079 | 1080 | static void op_szf_cb(u8_t arg0, u8_t arg1) 1081 | { 1082 | SET_Z(); 1083 | } 1084 | 1085 | static void op_rzf_cb(u8_t arg0, u8_t arg1) 1086 | { 1087 | CLEAR_Z(); 1088 | } 1089 | 1090 | static void op_sdf_cb(u8_t arg0, u8_t arg1) 1091 | { 1092 | SET_D(); 1093 | } 1094 | 1095 | static void op_rdf_cb(u8_t arg0, u8_t arg1) 1096 | { 1097 | CLEAR_D(); 1098 | } 1099 | 1100 | static void op_ei_cb(u8_t arg0, u8_t arg1) 1101 | { 1102 | SET_I(); 1103 | } 1104 | 1105 | static void op_di_cb(u8_t arg0, u8_t arg1) 1106 | { 1107 | CLEAR_I(); 1108 | } 1109 | 1110 | static void op_inc_sp_cb(u8_t arg0, u8_t arg1) 1111 | { 1112 | sp = (sp + 1) & 0xFF; 1113 | } 1114 | 1115 | static void op_dec_sp_cb(u8_t arg0, u8_t arg1) 1116 | { 1117 | sp = (sp - 1) & 0xFF; 1118 | } 1119 | 1120 | static void op_push_r_cb(u8_t arg0, u8_t arg1) 1121 | { 1122 | sp = (sp - 1) & 0xFF; 1123 | SET_M(sp, RQ(arg0)); 1124 | } 1125 | 1126 | static void op_push_xp_cb(u8_t arg0, u8_t arg1) 1127 | { 1128 | sp = (sp - 1) & 0xFF; 1129 | SET_M(sp, XP); 1130 | } 1131 | 1132 | static void op_push_xh_cb(u8_t arg0, u8_t arg1) 1133 | { 1134 | sp = (sp - 1) & 0xFF; 1135 | SET_M(sp, XH1); 1136 | } 1137 | 1138 | static void op_push_xl_cb(u8_t arg0, u8_t arg1) 1139 | { 1140 | sp = (sp - 1) & 0xFF; 1141 | SET_M(sp, XL1); 1142 | } 1143 | 1144 | static void op_push_yp_cb(u8_t arg0, u8_t arg1) 1145 | { 1146 | sp = (sp - 1) & 0xFF; 1147 | SET_M(sp, YP); 1148 | } 1149 | 1150 | static void op_push_yh_cb(u8_t arg0, u8_t arg1) 1151 | { 1152 | sp = (sp - 1) & 0xFF; 1153 | SET_M(sp, YH1); 1154 | } 1155 | 1156 | static void op_push_yl_cb(u8_t arg0, u8_t arg1) 1157 | { 1158 | sp = (sp - 1) & 0xFF; 1159 | SET_M(sp, YL1); 1160 | } 1161 | 1162 | static void op_push_f_cb(u8_t arg0, u8_t arg1) 1163 | { 1164 | sp = (sp - 1) & 0xFF; 1165 | SET_M(sp, flags); 1166 | } 1167 | 1168 | static void op_pop_r_cb(u8_t arg0, u8_t arg1) 1169 | { 1170 | SET_RQ(arg0, M(sp)); 1171 | sp = (sp + 1) & 0xFF; 1172 | } 1173 | 1174 | static void op_pop_xp_cb(u8_t arg0, u8_t arg1) 1175 | { 1176 | x = XL1 | (XH1 << 4)| (M(sp) << 8); 1177 | sp = (sp + 1) & 0xFF; 1178 | } 1179 | 1180 | static void op_pop_xh_cb(u8_t arg0, u8_t arg1) 1181 | { 1182 | x = XL1 | (M(sp) << 4)| (XP << 8); 1183 | sp = (sp + 1) & 0xFF; 1184 | } 1185 | 1186 | static void op_pop_xl_cb(u8_t arg0, u8_t arg1) 1187 | { 1188 | x = M(sp) | (XH1 << 4)| (XP << 8); 1189 | sp = (sp + 1) & 0xFF; 1190 | } 1191 | 1192 | static void op_pop_yp_cb(u8_t arg0, u8_t arg1) 1193 | { 1194 | y = YL1 | (YH1 << 4)| (M(sp) << 8); 1195 | sp = (sp + 1) & 0xFF; 1196 | } 1197 | 1198 | static void op_pop_yh_cb(u8_t arg0, u8_t arg1) 1199 | { 1200 | y = YL1 | (M(sp) << 4)| (YP << 8); 1201 | sp = (sp + 1) & 0xFF; 1202 | } 1203 | 1204 | static void op_pop_yl_cb(u8_t arg0, u8_t arg1) 1205 | { 1206 | y = M(sp) | (YH1 << 4)| (YP << 8); 1207 | sp = (sp + 1) & 0xFF; 1208 | } 1209 | 1210 | static void op_pop_f_cb(u8_t arg0, u8_t arg1) 1211 | { 1212 | flags = M(sp); 1213 | sp = (sp + 1) & 0xFF; 1214 | } 1215 | 1216 | static void op_ld_sph_r_cb(u8_t arg0, u8_t arg1) 1217 | { 1218 | sp = SPL1 | (RQ(arg0) << 4); 1219 | } 1220 | 1221 | static void op_ld_spl_r_cb(u8_t arg0, u8_t arg1) 1222 | { 1223 | sp = RQ(arg0) | (SPH1 << 4); 1224 | } 1225 | 1226 | static void op_ld_r_sph_cb(u8_t arg0, u8_t arg1) 1227 | { 1228 | SET_RQ(arg0, SPH1); 1229 | } 1230 | 1231 | static void op_ld_r_spl_cb(u8_t arg0, u8_t arg1) 1232 | { 1233 | SET_RQ(arg0, SPL1); 1234 | } 1235 | 1236 | static void op_add_r_i_cb(u8_t arg0, u8_t arg1) 1237 | { 1238 | u8_t tmp; 1239 | 1240 | tmp = RQ(arg0) + arg1; 1241 | if (D) { 1242 | if (tmp >= 10) { 1243 | SET_RQ(arg0, (tmp - 10) & 0xF); 1244 | SET_C(); 1245 | } else { 1246 | SET_RQ(arg0, tmp); 1247 | CLEAR_C(); 1248 | } 1249 | } else { 1250 | SET_RQ(arg0, tmp & 0xF); 1251 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1252 | } 1253 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1254 | } 1255 | 1256 | static void op_add_r_q_cb(u8_t arg0, u8_t arg1) 1257 | { 1258 | u8_t tmp; 1259 | 1260 | tmp = RQ(arg0) + RQ(arg1); 1261 | if (D) { 1262 | if (tmp >= 10) { 1263 | SET_RQ(arg0, (tmp - 10) & 0xF); 1264 | SET_C(); 1265 | } else { 1266 | SET_RQ(arg0, tmp); 1267 | CLEAR_C(); 1268 | } 1269 | } else { 1270 | SET_RQ(arg0, tmp & 0xF); 1271 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1272 | } 1273 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1274 | } 1275 | 1276 | static void op_adc_r_i_cb(u8_t arg0, u8_t arg1) 1277 | { 1278 | u8_t tmp; 1279 | 1280 | tmp = RQ(arg0) + arg1 + C; 1281 | if (D) { 1282 | if (tmp >= 10) { 1283 | SET_RQ(arg0, (tmp - 10) & 0xF); 1284 | SET_C(); 1285 | } else { 1286 | SET_RQ(arg0, tmp); 1287 | CLEAR_C(); 1288 | } 1289 | } else { 1290 | SET_RQ(arg0, tmp & 0xF); 1291 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1292 | } 1293 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1294 | } 1295 | 1296 | static void op_adc_r_q_cb(u8_t arg0, u8_t arg1) 1297 | { 1298 | u8_t tmp; 1299 | 1300 | tmp = RQ(arg0) + RQ(arg1) + C; 1301 | if (D) { 1302 | if (tmp >= 10) { 1303 | SET_RQ(arg0, (tmp - 10) & 0xF); 1304 | SET_C(); 1305 | } else { 1306 | SET_RQ(arg0, tmp); 1307 | CLEAR_C(); 1308 | } 1309 | } else { 1310 | SET_RQ(arg0, tmp & 0xF); 1311 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1312 | } 1313 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1314 | } 1315 | 1316 | static void op_sub_cb(u8_t arg0, u8_t arg1) 1317 | { 1318 | u8_t tmp; 1319 | 1320 | tmp = RQ(arg0) - RQ(arg1); 1321 | if (D) { 1322 | if (tmp >> 4) { 1323 | SET_RQ(arg0, (tmp - 6) & 0xF); 1324 | } else { 1325 | SET_RQ(arg0, tmp); 1326 | } 1327 | } else { 1328 | SET_RQ(arg0, tmp & 0xF); 1329 | } 1330 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1331 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1332 | } 1333 | 1334 | static void op_sbc_r_i_cb(u8_t arg0, u8_t arg1) 1335 | { 1336 | u8_t tmp; 1337 | 1338 | tmp = RQ(arg0) - arg1 - C; 1339 | if (D) { 1340 | if (tmp >> 4) { 1341 | SET_RQ(arg0, (tmp - 6) & 0xF); 1342 | } else { 1343 | SET_RQ(arg0, tmp); 1344 | } 1345 | } else { 1346 | SET_RQ(arg0, tmp & 0xF); 1347 | } 1348 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1349 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1350 | } 1351 | 1352 | static void op_sbc_r_q_cb(u8_t arg0, u8_t arg1) 1353 | { 1354 | u8_t tmp; 1355 | 1356 | tmp = RQ(arg0) - RQ(arg1) - C; 1357 | if (D) { 1358 | if (tmp >> 4) { 1359 | SET_RQ(arg0, (tmp - 6) & 0xF); 1360 | } else { 1361 | SET_RQ(arg0, tmp); 1362 | } 1363 | } else { 1364 | SET_RQ(arg0, tmp & 0xF); 1365 | } 1366 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1367 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1368 | } 1369 | 1370 | static void op_and_r_i_cb(u8_t arg0, u8_t arg1) 1371 | { 1372 | SET_RQ(arg0, RQ(arg0) & arg1); 1373 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1374 | } 1375 | 1376 | static void op_and_r_q_cb(u8_t arg0, u8_t arg1) 1377 | { 1378 | SET_RQ(arg0, RQ(arg0) & RQ(arg1)); 1379 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1380 | } 1381 | 1382 | static void op_or_r_i_cb(u8_t arg0, u8_t arg1) 1383 | { 1384 | SET_RQ(arg0, RQ(arg0) | arg1); 1385 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1386 | } 1387 | 1388 | static void op_or_r_q_cb(u8_t arg0, u8_t arg1) 1389 | { 1390 | SET_RQ(arg0, RQ(arg0) | RQ(arg1)); 1391 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1392 | } 1393 | 1394 | static void op_xor_r_i_cb(u8_t arg0, u8_t arg1) 1395 | { 1396 | SET_RQ(arg0, RQ(arg0) ^ arg1); 1397 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1398 | } 1399 | 1400 | static void op_xor_r_q_cb(u8_t arg0, u8_t arg1) 1401 | { 1402 | SET_RQ(arg0, RQ(arg0) ^ RQ(arg1)); 1403 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1404 | } 1405 | 1406 | static void op_cp_r_i_cb(u8_t arg0, u8_t arg1) 1407 | { 1408 | if (RQ(arg0) < arg1) { SET_C(); } else { CLEAR_C(); } 1409 | if (RQ(arg0) == arg1) { SET_Z(); } else { CLEAR_Z(); } 1410 | } 1411 | 1412 | static void op_cp_r_q_cb(u8_t arg0, u8_t arg1) 1413 | { 1414 | if (RQ(arg0) < RQ(arg1)) { SET_C(); } else { CLEAR_C(); } 1415 | if (RQ(arg0) == RQ(arg1)) { SET_Z(); } else { CLEAR_Z(); } 1416 | } 1417 | 1418 | static void op_fan_r_i_cb(u8_t arg0, u8_t arg1) 1419 | { 1420 | if (!(RQ(arg0) & arg1)) { SET_Z(); } else { CLEAR_Z(); } 1421 | } 1422 | 1423 | static void op_fan_r_q_cb(u8_t arg0, u8_t arg1) 1424 | { 1425 | if (!(RQ(arg0) & RQ(arg1))) { SET_Z(); } else { CLEAR_Z(); } 1426 | } 1427 | 1428 | static void op_rlc_cb(u8_t arg0, u8_t arg1) 1429 | { 1430 | u8_t tmp; 1431 | 1432 | tmp = (RQ(arg0) << 1) | C; 1433 | if (RQ(arg0) & 0x8) { SET_C(); } else { CLEAR_C(); } 1434 | SET_RQ(arg0, tmp & 0xF); 1435 | /* No need to set Z (issue in DS) */ 1436 | } 1437 | 1438 | static void op_rrc_cb(u8_t arg0, u8_t arg1) 1439 | { 1440 | u8_t tmp; 1441 | 1442 | tmp = (RQ(arg0) >> 1) | (C << 3); 1443 | if (RQ(arg0) & 0x1) { SET_C(); } else { CLEAR_C(); } 1444 | SET_RQ(arg0, tmp & 0xF); 1445 | /* No need to set Z (issue in DS) */ 1446 | } 1447 | 1448 | static void op_inc_mn_cb(u8_t arg0, u8_t arg1) 1449 | { 1450 | u8_t tmp; 1451 | 1452 | tmp = M(arg0) + 1; 1453 | SET_M(arg0, tmp & 0xF); 1454 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1455 | if (!M(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1456 | } 1457 | 1458 | static void op_dec_mn_cb(u8_t arg0, u8_t arg1) 1459 | { 1460 | u8_t tmp; 1461 | 1462 | tmp = M(arg0) - 1; 1463 | SET_M(arg0, tmp & 0xF); 1464 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1465 | if (!M(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1466 | } 1467 | 1468 | static void op_acpx_cb(u8_t arg0, u8_t arg1) 1469 | { 1470 | u8_t tmp; 1471 | 1472 | tmp = M(x) + RQ(arg0) + C; 1473 | if (D) { 1474 | if (tmp >= 10) { 1475 | SET_M(x, (tmp - 10) & 0xF); 1476 | SET_C(); 1477 | } else { 1478 | SET_M(x, tmp); 1479 | CLEAR_C(); 1480 | } 1481 | } else { 1482 | SET_M(x, tmp & 0xF); 1483 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1484 | } 1485 | if (!M(x)) { SET_Z(); } else { CLEAR_Z(); } 1486 | x = (x + 1) & 0xFFF; 1487 | } 1488 | 1489 | static void op_acpy_cb(u8_t arg0, u8_t arg1) 1490 | { 1491 | u8_t tmp; 1492 | 1493 | tmp = M(y) + RQ(arg0) + C; 1494 | if (D) { 1495 | if (tmp >= 10) { 1496 | SET_M(y, (tmp - 10) & 0xF); 1497 | SET_C(); 1498 | } else { 1499 | SET_M(y, tmp); 1500 | CLEAR_C(); 1501 | } 1502 | } else { 1503 | SET_M(y, tmp & 0xF); 1504 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1505 | } 1506 | if (!M(y)) { SET_Z(); } else { CLEAR_Z(); } 1507 | y = (y + 1) & 0xFFF; 1508 | } 1509 | 1510 | static void op_scpx_cb(u8_t arg0, u8_t arg1) 1511 | { 1512 | u8_t tmp; 1513 | 1514 | tmp = M(x) - RQ(arg0) - C; 1515 | if (D) { 1516 | if (tmp >> 4) { 1517 | SET_M(x, (tmp - 6) & 0xF); 1518 | } else { 1519 | SET_M(x, tmp); 1520 | } 1521 | } else { 1522 | SET_M(x, tmp & 0xF); 1523 | } 1524 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1525 | if (!M(x)) { SET_Z(); } else { CLEAR_Z(); } 1526 | x = (x + 1) & 0xFFF; 1527 | } 1528 | 1529 | static void op_scpy_cb(u8_t arg0, u8_t arg1) 1530 | { 1531 | u8_t tmp; 1532 | 1533 | tmp = M(y) - RQ(arg0) - C; 1534 | if (D) { 1535 | if (tmp >> 4) { 1536 | SET_M(y, (tmp - 6) & 0xF); 1537 | } else { 1538 | SET_M(y, tmp); 1539 | } 1540 | } else { 1541 | SET_M(y, tmp & 0xF); 1542 | } 1543 | if (tmp >> 4) { SET_C(); } else { CLEAR_C(); } 1544 | if (!M(y)) { SET_Z(); } else { CLEAR_Z(); } 1545 | y = (y + 1) & 0xFFF; 1546 | } 1547 | 1548 | static void op_not_cb(u8_t arg0, u8_t arg1) 1549 | { 1550 | SET_RQ(arg0, ~RQ(arg0) & 0xF); 1551 | if (!RQ(arg0)) { SET_Z(); } else { CLEAR_Z(); } 1552 | } 1553 | 1554 | /* The E0C6S46 supported instructions */ 1555 | static const op_t0 ops0[] PROGMEM = { 1556 | {0xE40, MASK_7B , 5 }, // PSET 1557 | {0x000, MASK_4B , 5 }, // JP 1558 | {0x200, MASK_4B , 5 }, // JP_C 1559 | {0x300, MASK_4B , 5 }, // JP_NC 1560 | {0x600, MASK_4B , 5 }, // JP_Z 1561 | {0x700, MASK_4B , 5 }, // JP_NZ 1562 | {0xFE8, MASK_12B , 5 }, // JPBA 1563 | {0x400, MASK_4B , 7 }, // CALL 1564 | {0x500, MASK_4B , 7 }, // CALZ 1565 | {0xFDF, MASK_12B , 7 }, // RET 1566 | {0xFDE, MASK_12B , 12}, // RETS 1567 | {0x100, MASK_4B , 12}, // RETD 1568 | {0xFFB, MASK_12B , 5 }, // NOP5 1569 | {0xFFF, MASK_12B , 7 }, // NOP7 1570 | {0xFF8, MASK_12B , 5 }, // HALT 1571 | {0xEE0, MASK_12B , 5 }, // INC_X 1572 | {0xEF0, MASK_12B , 5 }, // INC_Y 1573 | {0xB00, MASK_4B , 5 }, // LD_X 1574 | {0x800, MASK_4B , 5 }, // LD_Y 1575 | {0xE80, MASK_10B , 5 }, // LD_XP_R 1576 | {0xE84, MASK_10B , 5 }, // LD_XH_R 1577 | {0xE88, MASK_10B , 5 }, // LD_XL_R 1578 | {0xE90, MASK_10B , 5 }, // LD_YP_R 1579 | {0xE94, MASK_10B , 5 }, // LD_YH_R 1580 | {0xE98, MASK_10B , 5 }, // LD_YL_R 1581 | {0xEA0, MASK_10B , 5 }, // LD_R_XP 1582 | {0xEA4, MASK_10B , 5 }, // LD_R_XH 1583 | {0xEA8, MASK_10B , 5 }, // LD_R_XL 1584 | {0xEB0, MASK_10B , 5 }, // LD_R_YP 1585 | {0xEB4, MASK_10B , 5 }, // LD_R_YH 1586 | {0xEB8, MASK_10B , 5 }, // LD_R_YL 1587 | {0xA00, MASK_8B , 7 }, // ADC_XH 1588 | {0xA10, MASK_8B , 7 }, // ADC_XL 1589 | {0xA20, MASK_8B , 7 }, // ADC_YH 1590 | {0xA30, MASK_8B , 7 }, // ADC_YL 1591 | {0xA40, MASK_8B , 7 }, // CP_XH 1592 | {0xA50, MASK_8B , 7 }, // CP_XL 1593 | {0xA60, MASK_8B , 7 }, // CP_YH 1594 | {0xA70, MASK_8B , 7 }, // CP_YL 1595 | {0xFA0, MASK_8B , 5 }, // LD_A_MN 1596 | {0xFB0, MASK_8B , 5 }, // LD_B_MN 1597 | {0xF80, MASK_8B , 5 }, // LD_MN_A 1598 | {0xF90, MASK_8B , 5 }, // LD_MN_B 1599 | {0xE60, MASK_8B , 5 }, // LDPX_MX 1600 | {0xE70, MASK_8B , 5 }, // LDPY_MY 1601 | {0x900, MASK_4B , 5 }, // LBPX 1602 | {0xF40, MASK_8B , 7 }, // SET 1603 | {0xF50, MASK_8B , 7 }, // RST 1604 | {0xF41, MASK_12B , 7 }, // SCF 1605 | {0xF5E, MASK_12B , 7 }, // RCF 1606 | {0xF42, MASK_12B , 7 }, // SZF 1607 | {0xF5D, MASK_12B , 7 }, // RZF 1608 | {0xF44, MASK_12B , 7 }, // SDF 1609 | {0xF5B, MASK_12B , 7 }, // RDF 1610 | {0xF48, MASK_12B , 7 }, // EI 1611 | {0xF57, MASK_12B , 7 }, // DI 1612 | {0xFDB, MASK_12B , 5 }, // INC_SP 1613 | {0xFCB, MASK_12B , 5 }, // DEC_SP 1614 | {0xFC0, MASK_10B , 5 }, // PUSH_R 1615 | {0xFC4, MASK_12B , 5 }, // PUSH_XP 1616 | {0xFC5, MASK_12B , 5 }, // PUSH_XH 1617 | {0xFC6, MASK_12B , 5 }, // PUSH_XL 1618 | {0xFC7, MASK_12B , 5 }, // PUSH_YP 1619 | {0xFC8, MASK_12B , 5 }, // PUSH_YH 1620 | {0xFC9, MASK_12B , 5 }, // PUSH_YL 1621 | {0xFCA, MASK_12B , 5 }, // PUSH_F 1622 | {0xFD0, MASK_10B , 5 }, // POP_R 1623 | {0xFD4, MASK_12B , 5 }, // POP_XP 1624 | {0xFD5, MASK_12B , 5 }, // POP_XH 1625 | {0xFD6, MASK_12B , 5 }, // POP_XL 1626 | {0xFD7, MASK_12B , 5 }, // POP_YP 1627 | {0xFD8, MASK_12B , 5 }, // POP_YH 1628 | {0xFD9, MASK_12B , 5 }, // POP_YL 1629 | {0xFDA, MASK_12B , 5 }, // POP_F 1630 | {0xFE0, MASK_10B , 5 }, // LD_SPH_R 1631 | {0xFF0, MASK_10B , 5 }, // LD_SPL_R 1632 | {0xFE4, MASK_10B , 5 }, // LD_R_SPH 1633 | {0xFF4, MASK_10B , 5 }, // LD_R_SPL 1634 | {0xC00, MASK_6B , 7 }, // ADD_R_I 1635 | {0xC40, MASK_6B , 7 }, // ADC_R_I 1636 | {0xB40, MASK_6B , 7 }, // SBC_R_I 1637 | {0xC80, MASK_6B , 7 }, // AND_R_I 1638 | {0xCC0, MASK_6B , 7 }, // OR_R_I 1639 | {0xD00, MASK_6B , 7 }, // XOR_R_I 1640 | {0xDC0, MASK_6B , 7 }, // CP_R_I 1641 | {0xD80, MASK_6B , 7 }, // FAN_R_I 1642 | {0xE00, MASK_6B , 5 }, // LD_R_I 1643 | {0xA80, MASK_8B , 7 }, // ADD_R_Q 1644 | {0xA90, MASK_8B , 7 }, // ADC_R_Q 1645 | {0xAA0, MASK_8B , 7 }, // SUB 1646 | {0xAB0, MASK_8B , 7 }, // SBC_R_Q 1647 | {0xAC0, MASK_8B , 7 }, // AND_R_Q 1648 | {0xAD0, MASK_8B , 7 }, // OR_R_Q 1649 | {0xAE0, MASK_8B , 7 }, // XOR_R_Q 1650 | {0xEC0, MASK_8B , 5 }, // LD_R_Q 1651 | {0xEE0, MASK_8B , 5 }, // LDPX_R 1652 | {0xEF0, MASK_8B , 5 }, // LDPY_R 1653 | {0xF00, MASK_8B , 7 }, // CP_R_Q 1654 | {0xF10, MASK_8B , 7 }, // FAN_R_Q 1655 | 1656 | {0xAF0, MASK_8B , 7 }, // RLC 1657 | {0xE8C, MASK_10B , 5 }, // RRC 1658 | {0xF60, MASK_8B , 7 }, // INC_MN 1659 | {0xF70, MASK_8B , 7 }, // DEC_MN 1660 | {0xF28, MASK_10B , 7 }, // ACPX 1661 | {0xF2C, MASK_10B , 7 }, // ACPY 1662 | {0xF38, MASK_10B , 7 }, // SCPX 1663 | {0xF3C, MASK_10B , 7 }, // SCPY 1664 | {0xD0F, 0xFCF , 7 }, // NOT 1665 | {NULL, 0, 0, 0, NULL}, 1666 | }; 1667 | 1668 | /* The E0C6S46 supported instructions */ 1669 | static const op_t1 ops1[] PROGMEM = { 1670 | {&op_pset_cb}, // PSET 1671 | {&op_jp_cb}, // JP 1672 | {&op_jp_c_cb}, // JP_C 1673 | {&op_jp_nc_cb}, // JP_NC 1674 | {&op_jp_z_cb}, // JP_Z 1675 | {&op_jp_nz_cb}, // JP_NZ 1676 | {&op_jpba_cb}, // JPBA 1677 | {&op_call_cb}, // CALL 1678 | {&op_calz_cb}, // CALZ 1679 | {&op_ret_cb}, // RET 1680 | {&op_rets_cb}, // RETS 1681 | {&op_retd_cb}, // RETD 1682 | {&op_nop5_cb}, // NOP5 1683 | {&op_nop7_cb}, // NOP7 1684 | {&op_halt_cb}, // HALT 1685 | {&op_inc_x_cb}, // INC_X 1686 | {&op_inc_y_cb}, // INC_Y 1687 | {&op_ld_x_cb}, // LD_X 1688 | {&op_ld_y_cb}, // LD_Y 1689 | {&op_ld_xp_r_cb}, // LD_XP_R 1690 | {&op_ld_xh_r_cb}, // LD_XH_R 1691 | {&op_ld_xl_r_cb}, // LD_XL_R 1692 | {&op_ld_yp_r_cb}, // LD_YP_R 1693 | {&op_ld_yh_r_cb}, // LD_YH_R 1694 | {&op_ld_yl_r_cb}, // LD_YL_R 1695 | {&op_ld_r_xp_cb}, // LD_R_XP 1696 | {&op_ld_r_xh_cb}, // LD_R_XH 1697 | {&op_ld_r_xl_cb}, // LD_R_XL 1698 | {&op_ld_r_yp_cb}, // LD_R_YP 1699 | {&op_ld_r_yh_cb}, // LD_R_YH 1700 | {&op_ld_r_yl_cb}, // LD_R_YL 1701 | {&op_adc_xh_cb}, // ADC_XH 1702 | {&op_adc_xl_cb}, // ADC_XL 1703 | {&op_adc_yh_cb}, // ADC_YH 1704 | {&op_adc_yl_cb}, // ADC_YL 1705 | {&op_cp_xh_cb}, // CP_XH 1706 | {&op_cp_xl_cb}, // CP_XL 1707 | {&op_cp_yh_cb}, // CP_YH 1708 | {&op_cp_yl_cb}, // CP_YL 1709 | {&op_ld_a_mn_cb}, // LD_A_MN 1710 | {&op_ld_b_mn_cb}, // LD_B_MN 1711 | {&op_ld_mn_a_cb}, // LD_MN_A 1712 | {&op_ld_mn_b_cb}, // LD_MN_B 1713 | {&op_ldpx_mx_cb}, // LDPX_MX 1714 | {&op_ldpy_my_cb}, // LDPY_MY 1715 | {&op_lbpx_cb}, // LBPX 1716 | {&op_set_cb}, // SET 1717 | {&op_rst_cb}, // RST 1718 | {&op_scf_cb}, // SCF 1719 | {&op_rcf_cb}, // RCF 1720 | {&op_szf_cb}, // SZF 1721 | {&op_rzf_cb}, // RZF 1722 | {&op_sdf_cb}, // SDF 1723 | {&op_rdf_cb}, // RDF 1724 | {&op_ei_cb}, // EI 1725 | {&op_di_cb}, // DI 1726 | {&op_inc_sp_cb}, // INC_SP 1727 | {&op_dec_sp_cb}, // DEC_SP 1728 | {&op_push_r_cb}, // PUSH_R 1729 | {&op_push_xp_cb}, // PUSH_XP 1730 | {&op_push_xh_cb}, // PUSH_XH 1731 | {&op_push_xl_cb}, // PUSH_XL 1732 | {&op_push_yp_cb}, // PUSH_YP 1733 | {&op_push_yh_cb}, // PUSH_YH 1734 | {&op_push_yl_cb}, // PUSH_YL 1735 | {&op_push_f_cb}, // PUSH_F 1736 | {&op_pop_r_cb}, // POP_R 1737 | {&op_pop_xp_cb}, // POP_XP 1738 | {&op_pop_xh_cb}, // POP_XH 1739 | {&op_pop_xl_cb}, // POP_XL 1740 | {&op_pop_yp_cb}, // POP_YP 1741 | {&op_pop_yh_cb}, // POP_YH 1742 | {&op_pop_yl_cb}, // POP_YL 1743 | {&op_pop_f_cb}, // POP_F 1744 | {&op_ld_sph_r_cb}, // LD_SPH_R 1745 | {&op_ld_spl_r_cb}, // LD_SPL_R 1746 | {&op_ld_r_sph_cb}, // LD_R_SPH 1747 | {&op_ld_r_spl_cb}, // LD_R_SPL 1748 | {&op_add_r_i_cb}, // ADD_R_I 1749 | {&op_adc_r_i_cb}, // ADC_R_I 1750 | {&op_sbc_r_i_cb}, // SBC_R_I 1751 | {&op_and_r_i_cb}, // AND_R_I 1752 | {&op_or_r_i_cb}, // OR_R_I 1753 | {&op_xor_r_i_cb}, // XOR_R_I 1754 | {&op_cp_r_i_cb}, // CP_R_I 1755 | {&op_fan_r_i_cb}, // FAN_R_I 1756 | {&op_ld_r_i_cb}, // LD_R_I 1757 | {&op_add_r_q_cb}, // ADD_R_Q 1758 | {&op_adc_r_q_cb}, // ADC_R_Q 1759 | {&op_sub_cb}, // SUB 1760 | {&op_sbc_r_q_cb}, // SBC_R_Q 1761 | {&op_and_r_q_cb}, // AND_R_Q 1762 | {&op_or_r_q_cb}, // OR_R_Q 1763 | {&op_xor_r_q_cb}, // XOR_R_Q 1764 | {&op_ld_r_q_cb}, // LD_R_Q 1765 | {&op_ldpx_r_cb}, // LDPX_R 1766 | {&op_ldpy_r_cb}, // LDPY_R 1767 | {&op_cp_r_q_cb}, // CP_R_Q 1768 | {&op_fan_r_q_cb}, // FAN_R_Q 1769 | 1770 | {&op_rlc_cb}, // RLC 1771 | {&op_rrc_cb}, // RRC 1772 | {&op_inc_mn_cb}, // INC_MN 1773 | {&op_dec_mn_cb}, // DEC_MN 1774 | {&op_acpx_cb}, // ACPX 1775 | {&op_acpy_cb}, // ACPY 1776 | {&op_scpx_cb}, // SCPX 1777 | {&op_scpy_cb}, // SCPY 1778 | {&op_not_cb}, // NOT 1779 | {NULL} 1780 | }; 1781 | 1782 | u12_t getShiftArg0(u12_t code, u12_t mask) { 1783 | if (mask==MASK_6B || mask==0xFCF) return 4; 1784 | if (code==0xA80 || code==0xA90 || code==0xAA0 || code==0xAB0 || code==0xAC0 || code==0xAD0 || code==0xAE0 || code==0xEC0 || code==0xEE0 || code==0xEF0 || code==0xF00 || code==0xF10) return 2; 1785 | return 0; 1786 | } 1787 | 1788 | u12_t getMaskArg0(u12_t shiftArg, u12_t mask) { 1789 | if (mask==MASK_6B) return 0x030; 1790 | if (mask==MASK_8B && shiftArg==2) return 0x00C; 1791 | return 0; 1792 | } 1793 | 1794 | static timestamp_t wait_for_cycles(timestamp_t since, u8_t cycles) { 1795 | timestamp_t deadline; 1796 | 1797 | tick_counter += cycles; 1798 | 1799 | if (CPU_SPEED_RATIO == 0) { 1800 | /* Emulation will be as fast as possible */ 1801 | return g_hal->get_timestamp(); 1802 | } 1803 | 1804 | deadline = since + (cycles * ts_freq)/(TICK_FREQUENCY * CPU_SPEED_RATIO); 1805 | g_hal->sleep_until(deadline); 1806 | 1807 | return deadline; 1808 | } 1809 | 1810 | static void process_interrupts(void) 1811 | { 1812 | u8_t i; 1813 | 1814 | /* Process interrupts in priority order */ 1815 | for (i = 0; i < INT_SLOT_NUM; i++) { 1816 | if (interrupts[i].triggered) { 1817 | //printf("IT %u !\n", i); 1818 | SET_M(sp - 1, PCP); 1819 | SET_M(sp - 2, PCSH); 1820 | SET_M(sp - 3, PCSL); 1821 | sp = (sp - 3) & 0xFF; 1822 | CLEAR_I(); 1823 | np = TO_NP(NBP, 1); 1824 | pc = TO_PC(PCB, 1, interrupts[i].vector); 1825 | call_depth++; 1826 | 1827 | ref_ts = wait_for_cycles(ref_ts, 12); 1828 | interrupts[i].triggered = 0; 1829 | } 1830 | } 1831 | } 1832 | 1833 | static void print_state(u8_t op_num, u12_t op, u13_t addr) 1834 | { 1835 | } 1836 | 1837 | //static char logMsg[40]; 1838 | 1839 | void cpu_reset(void) 1840 | { 1841 | u13_t i; 1842 | 1843 | /* Registers and variables init */ 1844 | pc = TO_PC(0, 1, 0x00); // PC starts at bank 0, page 1, step 0 1845 | np = TO_NP(0, 1); // NP starts at page 1 1846 | a = 0; // undef 1847 | b = 0; // undef 1848 | x = 0; // undef 1849 | y = 0; // undef 1850 | sp = 0; // undef 1851 | flags = 0; 1852 | 1853 | //sprintf(logMsg, "Start pc 1:0x%04X, %d", pc, pc); g_hal->log(LOG_ERROR, logMsg); 1854 | 1855 | /* Init RAM to zeros */ 1856 | for (i = 0; i < MEMORY_SIZE; i++) { 1857 | memory[i] = 0; 1858 | } 1859 | /*for (i = 0; i < MEM_IO_SIZE; i++) { 1860 | io_memory[i] = 0; 1861 | } */ 1862 | 1863 | //io_memory[REG_K40_K43_BZ_OUTPUT_PORT - MEM_IO_ADDR_OFS] = 0xF; // Output port (R40-R43) 1864 | //io_memory[REG_LCD_CTRL - MEM_IO_ADDR_OFS] = 0x8; // LCD control 1865 | /* TODO: Input relation register */ 1866 | 1867 | cpu_sync_ref_timestamp(); 1868 | } 1869 | 1870 | bool_t cpu_init(u32_t freq) 1871 | { 1872 | //g_program = program; 1873 | //g_breakpoints = breakpoints; 1874 | ts_freq = freq; 1875 | cpu_reset(); 1876 | return 0; 1877 | } 1878 | 1879 | void cpu_release(void) 1880 | { 1881 | } 1882 | 1883 | u12_t getProgramOpCode(u12_t pc) { 1884 | u12_t i = pc >> 1; // divided by 2 1885 | if ((pc & 0x1)==0) { // if pc is a even number 1886 | return (pgm_read_byte_near(g_program_b12+i+i+i) << 4) | ((pgm_read_byte_near(g_program_b12+i+i+i+1) >> 4) & 0xF); 1887 | } 1888 | return (pgm_read_byte_near(g_program_b12+i+i+i+1) << 8) | pgm_read_byte_near(g_program_b12+i+i+i+2); 1889 | } 1890 | 1891 | /* 1892 | typedef struct { 1893 | u12_t code; 1894 | u12_t mask; 1895 | u8_t cycles; 1896 | } op_t0; 1897 | */ 1898 | 1899 | int cpu_step(void) 1900 | { 1901 | u12_t op; 1902 | u8_t i; 1903 | //breakpoint_t *bp = g_breakpoints; 1904 | static u8_t previous_cycles = 0; 1905 | 1906 | op = getProgramOpCode(pc); 1907 | 1908 | //op_t0 *ops = (op_t0 *)pgm_read_ptr_near(ops0); 1909 | 1910 | /* Lookup the OP code */ 1911 | for (i = 0; pgm_read_byte_near(&ops0[i].cycles) != 0; i++) { 1912 | if ((op & pgm_read_word_near(&ops0[i].mask)) == pgm_read_word_near(&ops0[i].code)) { 1913 | break; 1914 | } 1915 | } 1916 | 1917 | //sprintf(logMsg, "op-code 0x%X (pc = 0x%04X)", op, pc); g_hal->log(LOG_ERROR, logMsg); 1918 | 1919 | if (pgm_read_byte_near(&ops0[i].cycles) == 0) { 1920 | //printf(logMsg, "Unknown op-code 0x%X (pc = 0x%04X)\n", op, pc); g_hal->log(LOG_ERROR, logMsg); 1921 | return 1; 1922 | } 1923 | 1924 | op_t0 ops; 1925 | ops.code=pgm_read_word_near(&ops0[i].code); 1926 | ops.mask=pgm_read_word_near(&ops0[i].mask); 1927 | ops.cycles=pgm_read_byte_near(&ops0[i].cycles); 1928 | 1929 | next_pc = (pc + 1) & 0x1FFF; 1930 | 1931 | /* Display the operation along with the current state of the processor */ 1932 | print_state(i, op, pc); 1933 | 1934 | /* Match the speed of the real processor 1935 | * NOTE: For better accuracy, the final wait should happen here, however 1936 | * the downside is that all interrupts will likely be delayed by one OP 1937 | */ 1938 | ref_ts = wait_for_cycles(ref_ts, previous_cycles); 1939 | 1940 | op_t1 ops11; 1941 | ops11.cb1 = pgm_read_ptr_near(&ops1[i].cb1); 1942 | 1943 | /* Process the OP code */ 1944 | if (ops11.cb1 != NULL) { 1945 | u12_t shiftArg0 = getShiftArg0(ops.code,ops.mask); 1946 | u12_t maskArg0 = getMaskArg0(shiftArg0,ops.mask); 1947 | if (maskArg0 != 0) { 1948 | /* Two arguments */ 1949 | //ops[i].cb((op & ops[i].mask_arg0) >> ops[i].shift_arg0, op & ~(ops[i].mask | ops[i].mask_arg0)); 1950 | ops11.cb1((op & maskArg0) >> shiftArg0, op & ~(ops.mask | maskArg0)); 1951 | } else { 1952 | /* One arguments */ 1953 | //ops[i].cb((op & ~ops[i].mask) >> ops[i].shift_arg0, 0); 1954 | ops11.cb1((op & ~ops.mask) >> shiftArg0, 0); 1955 | } 1956 | } 1957 | 1958 | /* Prepare for the next instruction */ 1959 | pc = next_pc; 1960 | previous_cycles = ops.cycles; 1961 | 1962 | if (i > 0) { 1963 | /* OP code is not PSET, reset NP */ 1964 | np = (pc >> 8) & 0x1F; 1965 | } 1966 | 1967 | /* Handle timers using the internal tick counter */ 1968 | if (tick_counter - clk_timer_timestamp >= TIMER_1HZ_PERIOD) { 1969 | do { 1970 | clk_timer_timestamp += TIMER_1HZ_PERIOD; 1971 | } while (tick_counter - clk_timer_timestamp >= TIMER_1HZ_PERIOD); 1972 | 1973 | generate_interrupt(INT_CLOCK_TIMER_SLOT, 3); 1974 | } 1975 | 1976 | if (prog_timer_enabled && tick_counter - prog_timer_timestamp >= TIMER_256HZ_PERIOD) { 1977 | do { 1978 | prog_timer_timestamp += TIMER_256HZ_PERIOD; 1979 | prog_timer_data--; 1980 | 1981 | if (prog_timer_data == 0) { 1982 | prog_timer_data = prog_timer_rld; 1983 | generate_interrupt(INT_PROG_TIMER_SLOT, 0); 1984 | } 1985 | } while (tick_counter - prog_timer_timestamp >= TIMER_256HZ_PERIOD); 1986 | } 1987 | 1988 | /* Check if there is any pending interrupt */ 1989 | if (I && i > 0) { // Do not process interrupts after a PSET operation 1990 | process_interrupts(); 1991 | } 1992 | 1993 | /* Check if we could pause the execution */ 1994 | /*while (bp != NULL) { 1995 | if (bp->addr == pc) { 1996 | return 1; 1997 | } 1998 | 1999 | bp = bp->next; 2000 | } */ 2001 | 2002 | return 0; 2003 | } 2004 | -------------------------------------------------------------------------------- /cpu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _CPU_H_ 21 | #define _CPU_H_ 22 | 23 | #include "hal.h" 24 | 25 | #define MEMORY_SIZE 0x140 // MEM_RAM_SIZE + MEM_IO_SIZE 26 | 27 | #define MEM_RAM_ADDR 0x000 28 | #define MEM_RAM_SIZE 0x280 29 | 30 | #define MEM_DISPLAY1_ADDR 0xE00 31 | #define MEM_DISPLAY1_ADDR_OFS 0xB80 32 | #define MEM_DISPLAY1_SIZE 0x050 33 | 34 | #define MEM_DISPLAY2_ADDR 0xE80 35 | #define MEM_DISPLAY2_ADDR_OFS 0xBB0 36 | #define MEM_DISPLAY2_SIZE 0x050 37 | 38 | #define MEM_IO_ADDR 0xF00 39 | //#define MEM_IO_ADDR_OFS 0xBE0 40 | #define MEM_IO_ADDR_OFS 0xF00 41 | #define MEM_IO_SIZE 0x080 42 | 43 | typedef struct breakpoint { 44 | u13_t addr; 45 | struct breakpoint *next; 46 | } breakpoint_t; 47 | 48 | 49 | typedef struct { 50 | u4_t factor_flag_reg; 51 | u4_t mask_reg; 52 | bool_t triggered; /* 1 if triggered, 0 otherwise */ 53 | u8_t vector; 54 | } interrupt_t; 55 | 56 | typedef struct { 57 | u13_t pc; 58 | u12_t x; 59 | u12_t y; 60 | u4_t a; 61 | u4_t b; 62 | u5_t np; 63 | u8_t sp; 64 | u4_t flags; 65 | u32_t tick_counter; 66 | u32_t clk_timer_timestamp; 67 | u32_t prog_timer_timestamp; 68 | bool_t prog_timer_enabled; 69 | u8_t prog_timer_data; 70 | u8_t prog_timer_rld; 71 | u32_t call_depth; 72 | u4_t *memory; 73 | interrupt_t interrupts[6]; 74 | } cpu_state_t; 75 | 76 | /* Pins (TODO: add other pins) */ 77 | typedef enum { 78 | PIN_K00 = 0x0, 79 | PIN_K01 = 0x1, 80 | PIN_K02 = 0x2, 81 | PIN_K03 = 0x3, 82 | PIN_K10 = 0X4, 83 | PIN_K11 = 0X5, 84 | PIN_K12 = 0X6, 85 | PIN_K13 = 0X7, 86 | } pin_t; 87 | 88 | typedef enum { 89 | PIN_STATE_LOW = 0, 90 | PIN_STATE_HIGH = 1, 91 | } pin_state_t; 92 | 93 | typedef enum { 94 | INT_PROG_TIMER_SLOT = 0, 95 | INT_SERIAL_SLOT = 1, 96 | INT_K10_K13_SLOT = 2, 97 | INT_K00_K03_SLOT = 3, 98 | INT_STOPWATCH_SLOT = 4, 99 | INT_CLOCK_TIMER_SLOT = 5, 100 | INT_SLOT_NUM, 101 | } int_slot_t; 102 | 103 | 104 | /* 105 | typedef struct { 106 | u13_t *pc; 107 | u12_t *x; 108 | u12_t *y; 109 | u4_t *a; 110 | u4_t *b; 111 | u5_t *np; 112 | u8_t *sp; 113 | u4_t *flags; 114 | 115 | u32_t *tick_counter; 116 | u32_t *clk_timer_timestamp; 117 | u32_t *prog_timer_timestamp; 118 | bool_t *prog_timer_enabled; 119 | u8_t *prog_timer_data; 120 | u8_t *prog_timer_rld; 121 | 122 | u32_t *call_depth; 123 | 124 | interrupt_t *interrupts; 125 | 126 | u4_t *memory; 127 | } state_t; */ 128 | 129 | #ifdef __cplusplus 130 | extern "C" { 131 | #endif 132 | 133 | void cpu_add_bp(breakpoint_t **list, u13_t addr); 134 | void cpu_free_bp(breakpoint_t **list); 135 | 136 | //void cpu_set_speed(u8_t speed); 137 | 138 | void cpu_get_state(cpu_state_t *cpustate); 139 | void cpu_set_state(cpu_state_t *cpustate); 140 | 141 | u32_t cpu_get_depth(void); 142 | 143 | void cpu_set_input_pin(pin_t pin, pin_state_t state); 144 | 145 | void cpu_sync_ref_timestamp(void); 146 | 147 | void cpu_refresh_hw(void); 148 | 149 | void cpu_reset(void); 150 | 151 | //u8_t cpu_get_max_number(void); 152 | 153 | //bool_t cpu_init(breakpoint_t *breakpoints, u32_t freq); 154 | 155 | bool_t cpu_init(u32_t freq); 156 | void cpu_release(void); 157 | 158 | int cpu_step(void); 159 | 160 | #ifdef __cplusplus 161 | } 162 | #endif 163 | 164 | #endif /* _CPU_H_ */ 165 | -------------------------------------------------------------------------------- /hal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _HAL_H_ 21 | #define _HAL_H_ 22 | 23 | #include "hal_types.h" 24 | 25 | #ifndef NULL 26 | #define NULL 0 27 | #endif 28 | 29 | typedef enum { 30 | LOG_ERROR = 0x1, 31 | LOG_INFO = (0x1 << 1), 32 | LOG_MEMORY = (0x1 << 2), 33 | LOG_CPU = (0x1 << 3), 34 | } log_level_t; 35 | 36 | /* The Hardware Abstraction Layer 37 | * NOTE: This structure acts as an abstraction layer between TamaLIB and the OS/SDK. 38 | * All pointers MUST be implemented, but some implementations can be left empty. 39 | */ 40 | typedef struct { 41 | /* Memory allocation functions 42 | * NOTE: Needed only if breakpoints support is required. 43 | */ 44 | //void * (*malloc)(u32_t size); 45 | //void (*free)(void *ptr); 46 | 47 | /* What to do if the CPU has halted 48 | */ 49 | void (*halt)(void); 50 | 51 | /* Log related function 52 | * NOTE: Needed only if log messages are required. 53 | */ 54 | //bool_t (*is_log_enabled)(log_level_t level); 55 | void (*log)(log_level_t level, char *buff, ...); 56 | 57 | /* Clock related functions 58 | * NOTE: Timestamps granularity is configured with tamalib_init(), an accuracy 59 | * of ~30 us (1/32768) is required for a cycle accurate emulation. 60 | */ 61 | void (*sleep_until)(timestamp_t ts); 62 | timestamp_t (*get_timestamp)(void); 63 | 64 | /* Screen related functions 65 | * NOTE: In case of direct hardware access to pixels, the set_XXXX() functions 66 | * (called for each pixel/icon update) can directly drive them, otherwise they 67 | * should just store the data in a buffer and let update_screen() do the actual 68 | * rendering (at 30 fps). 69 | */ 70 | void (*update_screen)(void); 71 | void (*set_lcd_matrix)(u8_t x, u8_t y, bool_t val); 72 | void (*set_lcd_icon)(u8_t icon, bool_t val); 73 | 74 | /* Sound related functions 75 | * NOTE: set_frequency() changes the output frequency of the sound, while 76 | * play_frequency() decides whether the sound should be heard or not. 77 | */ 78 | void (*set_frequency)(u32_t freq); 79 | void (*play_frequency)(bool_t en); 80 | 81 | /* Event handler from the main app (if any) 82 | * NOTE: This function usually handles button related events, states loading/saving ... 83 | */ 84 | int (*handler)(void); 85 | } hal_t; 86 | 87 | extern hal_t *g_hal; 88 | 89 | #endif /* _HAL_H_ */ 90 | -------------------------------------------------------------------------------- /hal_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaTool - A cross-platform Tamagotchi P1 explorer 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _HAL_TYPES_H_ 21 | #define _HAL_TYPES_H_ 22 | 23 | #include 24 | 25 | typedef uint8_t bool_t; 26 | typedef uint8_t u4_t; 27 | typedef uint8_t u5_t; 28 | typedef uint8_t u8_t; 29 | typedef uint16_t u12_t; 30 | typedef uint16_t u13_t; 31 | typedef uint32_t u32_t; 32 | typedef uint32_t timestamp_t; // WARNING: Must be an unsigned type to properly handle wrapping (u32 wraps in around 1h11m when expressed in us) 33 | 34 | #endif /* _HAL_TYPES_H_ */ 35 | -------------------------------------------------------------------------------- /hardcoded_state.h: -------------------------------------------------------------------------------- 1 | static const uint8_t hardcodedState[] PROGMEM = { 2 | 0xB4,0x04,0x6D,0x00,0x2D,0x00,0x00,0x01,0x04,0xF9,0x0B,0x77,0x3C,0xFC,0xBC,0x00, 3 | 0x00,0xFC,0xBC,0x5C,0x3C,0xFC,0xBC,0x01,0x01,0x07,0x02,0x00,0x00,0x00,0xC2,0x03, 4 | 0x00,0x01,0x00,0x0C,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x08,0x07,0x00,0x00,0x06, 5 | 0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x02,0x01,0x30,0xE0,0x53,0x38,0x00,0x00,0x00, 6 | 0x63,0x54,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEA,0x00,0x00,0x00,0x00,0x18, 7 | 0xF9,0x75,0x80,0xD7,0xFA,0x09,0xF0,0x80,0xFC,0xF0,0x00,0x62,0x70,0x0F,0x00,0x00, 8 | 0xF6,0x00,0x50,0x08,0x0F,0x70,0x0A,0x10,0x00,0x13,0xAC,0x00,0x01,0xB9,0x01,0x10, 9 | 0xC0,0x01,0xF0,0x8A,0x00,0x0F,0xFF,0x50,0x10,0x50,0x80,0x00,0x00,0x00,0x00,0x00, 10 | 0xFF,0xC1,0xFF,0xC1,0xD1,0xFF,0xD1,0xFF,0x00,0xF7,0x05,0xB2,0xF3,0x00,0x00,0x00, 11 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 12 | 0x00,0x00,0x77,0x4B,0x17,0x77,0x17,0x71,0x01,0x07,0x71,0x77,0x1D,0x70,0x00,0x21, 13 | 0x77,0x1A,0xE1,0x78,0x44,0x50,0x24,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 14 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 15 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 16 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 17 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 18 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 19 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 20 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 21 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xF0,0xFF,0x99,0x00,0x00,0x0E,0x52, 22 | 0x80,0x56,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 23 | 0xA0,0x61,0xD2,0x23,0x49,0x2C,0x02,0x99,0x0A,0x57,0x08,0x11,0x10,0x00,0x00,0x00, 24 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 25 | 0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; 26 | 27 | /* Stage 3 28 | static const uint8_t hardcodedState[] PROGMEM = { 29 | 0xEF,0x00,0x48,0x00,0x01,0x02,0x06,0x00,0x00,0xEF,0x01,0x5B,0x74,0x91,0x70,0x00, 30 | 0x00,0x91,0x70,0xDC,0x73,0x91,0x70,0x01,0x02,0x07,0x04,0x00,0x00,0x00,0xC2,0x03, 31 | 0x00,0x01,0x00,0x0C,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x08,0x07,0x00,0x00,0x06, 32 | 0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x02,0x0B,0x00,0xF0,0x45,0x80,0x00,0x00,0x00, 33 | 0x85,0x82,0xD0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x00,0x00,0x00,0x00,0x12, 34 | 0x21,0x18,0x80,0xD7,0x9D,0x89,0xF0,0xB0,0xB4,0xF0,0x00,0x42,0x70,0x0F,0x00,0x00, 35 | 0x53,0x00,0x30,0x0A,0x0F,0xB0,0x04,0x11,0x00,0x10,0xBC,0x00,0x30,0x9D,0x81,0x01, 36 | 0xF0,0x00,0xF0,0x8A,0x00,0x0F,0xF0,0x70,0x30,0x05,0x80,0x00,0x00,0x00,0x00,0x00, 37 | 0x13,0x23,0x33,0xFF,0xC1,0xD1,0xD1,0xD1,0x00,0xF7,0x05,0xB2,0xF3,0x10,0x00,0x00, 38 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 39 | 0x00,0x00,0x77,0x17,0x77,0x77,0x17,0x71,0x77,0x17,0x71,0x77,0x18,0x40,0x00,0x3E, 40 | 0x00,0x68,0x40,0xDD,0x0F,0x8F,0xE2,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 41 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x40,0xA0,0x20,0x20,0x20,0xA0,0x40, 42 | 0x8A,0x8A,0x8A,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 43 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 44 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 45 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x40,0x80,0x80,0x80,0x80,0x80,0x80,0x40, 46 | 0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 47 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 48 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x52,0xFF,0xE6,0x00,0x00,0x0D,0x02, 49 | 0xDD,0x44,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 50 | 0x90,0x51,0xB4,0x55,0x49,0x2C,0x02,0x99,0x46,0x56,0x08,0x11,0x00,0x00,0x00,0x00, 51 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 52 | 0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; 53 | */ 54 | -------------------------------------------------------------------------------- /hw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | //#include 21 | #include "hw.h" 22 | #include "cpu.h" 23 | #include "hal.h" 24 | 25 | /* SEG -> LCD mapping */ 26 | const static u8_t seg_pos[40] = {0, 1, 2, 3, 4, 5, 6, 7, 32, 8, 9, 10, 11, 12 ,13 ,14, 15, 33, 34, 35, 31, 30, 29, 28, 27, 26, 25, 24, 36, 23, 22, 21, 20, 19, 18, 17, 16, 37, 38, 39}; 27 | 28 | 29 | bool_t hw_init(void) 30 | { 31 | /* Buttons are active LOW */ 32 | cpu_set_input_pin(PIN_K00, PIN_STATE_HIGH); 33 | cpu_set_input_pin(PIN_K01, PIN_STATE_HIGH); 34 | cpu_set_input_pin(PIN_K02, PIN_STATE_HIGH); 35 | return 0; 36 | } 37 | 38 | void hw_release(void) 39 | { 40 | } 41 | 42 | void hw_set_lcd_pin(u8_t seg, u8_t com, u8_t val) 43 | { 44 | if (seg_pos[seg] < LCD_WIDTH) { 45 | g_hal->set_lcd_matrix(seg_pos[seg], com, val); 46 | } else { 47 | /* 48 | * IC n -> seg-com|... 49 | * IC 0 -> 8-0 |18-3 |19-2 50 | * IC 1 -> 8-1 |17-0 |19-3 51 | * IC 2 -> 8-2 |17-1 |37-12|38-13|39-14 52 | * IC 3 -> 8-3 |17-2 |18-1 |19-0 53 | * IC 4 -> 28-12|37-13|38-14|39-15 54 | * IC 5 -> 28-13|37-14|38-15 55 | * IC 6 -> 28-14|37-15|39-12 56 | * IC 7 -> 28-15|38-12|39-13 57 | */ 58 | if (seg == 8 && com < 4) { 59 | g_hal->set_lcd_icon(com, val); 60 | } else if (seg == 28 && com >= 12) { 61 | g_hal->set_lcd_icon(com - 8, val); 62 | } 63 | } 64 | } 65 | 66 | void hw_set_button(button_t btn, btn_state_t state) 67 | { 68 | pin_state_t pin_state = (state == BTN_STATE_PRESSED) ? PIN_STATE_LOW : PIN_STATE_HIGH; 69 | 70 | switch (btn) { 71 | case BTN_LEFT: 72 | cpu_set_input_pin(PIN_K02, pin_state); 73 | break; 74 | 75 | case BTN_MIDDLE: 76 | cpu_set_input_pin(PIN_K01, pin_state); 77 | break; 78 | 79 | case BTN_RIGHT: 80 | cpu_set_input_pin(PIN_K00, pin_state); 81 | break; 82 | } 83 | } 84 | 85 | const static uint16_t snd_freq[]= {4096,3279,2731,2341,2048,1638,1365,1170}; 86 | void hw_set_buzzer_freq(u4_t freq) 87 | { 88 | if (freq>7) return; 89 | g_hal->set_frequency(snd_freq[freq]); 90 | /*u32_t snd_freq = 0; 91 | 92 | switch (freq) { 93 | case 0: 94 | // 4096.0 Hz 95 | snd_freq = 4096; 96 | break; 97 | 98 | case 1: 99 | // 3276.8 Hz 100 | snd_freq = 3279; 101 | break; 102 | 103 | case 2: 104 | // 2730.7 Hz 105 | snd_freq = 2731; 106 | break; 107 | 108 | case 3: 109 | // 2340.6 Hz 110 | snd_freq = 2341; 111 | break; 112 | 113 | case 4: 114 | // 2048.0 Hz 115 | snd_freq = 2048; 116 | break; 117 | 118 | case 5: 119 | // 1638.4 Hz 120 | snd_freq = 1638; 121 | break; 122 | 123 | case 6: 124 | // 1365.3 Hz 125 | snd_freq = 1365; 126 | break; 127 | 128 | case 7: 129 | // 1170.3 Hz 130 | snd_freq = 1170; 131 | break; 132 | } 133 | 134 | if (snd_freq != 0) { 135 | g_hal->set_frequency(snd_freq); 136 | }*/ 137 | } 138 | 139 | void hw_enable_buzzer(bool_t en) 140 | { 141 | g_hal->play_frequency(en); 142 | } 143 | -------------------------------------------------------------------------------- /hw.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _HW_H_ 21 | #define _HW_H_ 22 | 23 | #include "hal.h" 24 | 25 | #define LCD_WIDTH 32 26 | #define LCD_HEIGHT 16 27 | 28 | #define ICON_NUM 8 29 | 30 | typedef enum { 31 | BTN_STATE_RELEASED = 0, 32 | BTN_STATE_PRESSED, 33 | } btn_state_t; 34 | 35 | typedef enum { 36 | BTN_LEFT = 0, 37 | BTN_MIDDLE, 38 | BTN_RIGHT, 39 | } button_t; 40 | 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | bool_t hw_init(void); 47 | void hw_release(void); 48 | 49 | void hw_set_lcd_pin(u8_t seg, u8_t com, u8_t val); 50 | void hw_set_button(button_t btn, btn_state_t state); 51 | 52 | void hw_set_buzzer_freq(u4_t freq); 53 | void hw_enable_buzzer(bool_t en); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif /* _HW_H_ */ 60 | -------------------------------------------------------------------------------- /images/Compile_and_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaryZ88/ArduinoGotchi/900b4192c450cb692b91690aea7658d4016d563d/images/Compile_and_upload.png -------------------------------------------------------------------------------- /images/TamaP1_devices.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaryZ88/ArduinoGotchi/900b4192c450cb692b91690aea7658d4016d563d/images/TamaP1_devices.jpg -------------------------------------------------------------------------------- /images/circuit_diagram_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaryZ88/ArduinoGotchi/900b4192c450cb692b91690aea7658d4016d563d/images/circuit_diagram_01.png -------------------------------------------------------------------------------- /tamalib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #include "tamalib.h" 21 | #include "hw.h" 22 | #include "cpu.h" 23 | #include "hal.h" 24 | 25 | #define DEFAULT_FRAMERATE 3// fps 26 | 27 | static exec_mode_t exec_mode = EXEC_MODE_RUN; 28 | 29 | static u32_t step_depth = 0; 30 | 31 | static timestamp_t screen_ts = 0; 32 | 33 | static u32_t ts_freq; 34 | 35 | static u8_t g_framerate = DEFAULT_FRAMERATE; 36 | 37 | hal_t *g_hal; 38 | 39 | 40 | bool_t tamalib_init(u32_t freq) 41 | //bool_t tamalib_init(breakpoint_t *breakpoints, u32_t freq) 42 | { 43 | bool_t res = 0; 44 | res |= cpu_init( freq); 45 | 46 | // res |= cpu_init(program, breakpoints, freq); 47 | res |= hw_init(); 48 | 49 | ts_freq = freq; 50 | 51 | return res; 52 | } 53 | 54 | /* 55 | void tamalib_release(void) 56 | { 57 | hw_release(); 58 | cpu_release(); 59 | }*/ 60 | 61 | 62 | void tamalib_set_framerate(u8_t framerate) 63 | { 64 | g_framerate = framerate; 65 | } 66 | /* 67 | u8_t tamalib_get_framerate(void) 68 | { 69 | 70 | //return g_framerate; 71 | return DEFAULT_FRAMERATE; 72 | } 73 | */ 74 | void tamalib_register_hal(hal_t *hal) 75 | { 76 | g_hal = hal; 77 | } 78 | /* 79 | void tamalib_set_exec_mode(exec_mode_t mode) 80 | { 81 | exec_mode = mode; 82 | step_depth = cpu_get_depth(); 83 | cpu_sync_ref_timestamp(); 84 | } 85 | */ 86 | 87 | /* 88 | void tamalib_step(void) 89 | { 90 | if (exec_mode == EXEC_MODE_PAUSE) { 91 | return; 92 | } 93 | 94 | if (cpu_step()) { 95 | exec_mode = EXEC_MODE_PAUSE; 96 | step_depth = cpu_get_depth(); 97 | } else { 98 | switch (exec_mode) { 99 | case EXEC_MODE_PAUSE: 100 | case EXEC_MODE_RUN: 101 | break; 102 | 103 | case EXEC_MODE_STEP: 104 | exec_mode = EXEC_MODE_PAUSE; 105 | break; 106 | 107 | case EXEC_MODE_NEXT: 108 | if (cpu_get_depth() <= step_depth) { 109 | exec_mode = EXEC_MODE_PAUSE; 110 | step_depth = cpu_get_depth(); 111 | } 112 | break; 113 | 114 | case EXEC_MODE_TO_CALL: 115 | if (cpu_get_depth() > step_depth) { 116 | exec_mode = EXEC_MODE_PAUSE; 117 | step_depth = cpu_get_depth(); 118 | } 119 | break; 120 | 121 | case EXEC_MODE_TO_RET: 122 | if (cpu_get_depth() < step_depth) { 123 | exec_mode = EXEC_MODE_PAUSE; 124 | step_depth = cpu_get_depth(); 125 | } 126 | break; 127 | } 128 | } 129 | } 130 | */ 131 | /* 132 | void tamalib_mainloop(void) 133 | { 134 | timestamp_t ts; 135 | 136 | while (!g_hal->handler()) { 137 | tamalib_step(); 138 | 139 | ts = g_hal->get_timestamp(); 140 | if (ts - screen_ts >= ts_freq/g_framerate) { 141 | screen_ts = ts; 142 | g_hal->update_screen(); 143 | } 144 | } 145 | } */ 146 | 147 | void tamalib_mainloop_step_by_step(void) 148 | { 149 | timestamp_t ts; 150 | 151 | if (!g_hal->handler()) { 152 | //tamalib_step(); 153 | 154 | if (exec_mode == EXEC_MODE_RUN) { 155 | if (cpu_step()) { 156 | exec_mode = EXEC_MODE_PAUSE; 157 | step_depth = cpu_get_depth(); 158 | } 159 | } 160 | 161 | 162 | /* Update the screen @ g_framerate fps */ 163 | ts = g_hal->get_timestamp(); 164 | 165 | if (ts - screen_ts >= ts_freq/g_framerate) { 166 | //if (ts - screen_ts >= ts_freq/DEFAULT_FRAMERATE) { 167 | screen_ts = ts; 168 | g_hal->update_screen(); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /tamalib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _TAMALIB_H_ 21 | #define _TAMALIB_H_ 22 | 23 | #include "cpu.h" 24 | #include "hw.h" 25 | #include "hal.h" 26 | 27 | #define tamalib_set_button(btn, state) hw_set_button(btn, state) 28 | 29 | #define tamalib_set_speed(speed) cpu_set_speed(speed) 30 | 31 | //#define tamalib_get_state() cpu_get_state() 32 | #define tamalib_refresh_hw() cpu_refresh_hw() 33 | 34 | #define tamalib_reset() cpu_reset() 35 | 36 | //#define tamalib_add_bp(list, addr) cpu_add_bp(list, addr) 37 | //#define tamalib_free_bp(list) cpu_free_bp(list) 38 | 39 | typedef enum { 40 | EXEC_MODE_PAUSE, 41 | EXEC_MODE_RUN, 42 | EXEC_MODE_STEP, 43 | EXEC_MODE_NEXT, 44 | EXEC_MODE_TO_CALL, 45 | EXEC_MODE_TO_RET, 46 | } exec_mode_t; 47 | 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | //void tamalib_release(void); 54 | bool_t tamalib_init(u32_t freq); 55 | //bool_t tamalib_init( breakpoint_t *breakpoints, u32_t freq); 56 | 57 | 58 | void tamalib_set_framerate(u8_t framerate); 59 | //u8_t tamalib_get_framerate(void); 60 | 61 | void tamalib_register_hal(hal_t *hal); 62 | 63 | //void tamalib_set_exec_mode(exec_mode_t mode); 64 | 65 | /* NOTE: Only one of these two functions must be used in the main application 66 | * (tamalib_step() should be used only if tamalib_mainloop() does not fit the 67 | * main application execution flow). 68 | */ 69 | //void tamalib_step(void); 70 | //void tamalib_mainloop(void); 71 | void tamalib_mainloop_step_by_step(void); 72 | #ifdef __cplusplus 73 | } 74 | #endif 75 | 76 | #endif /* _TAMALIB_H_ */ 77 | --------------------------------------------------------------------------------