| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- /*
- MSP430 Emulator
- Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)
- "MSP430 Emulator" is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- "MSP430 Emulator" is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #include "port1.h"
- /* Cheat Sheet:
- * PxIN : 0 = LOW input, 1 = HIGH input
- * PxOUT: 0 = LOW output, 1 = HIGH output
- * PxDIR: 0 = INPUT, 1 = OUTPUT
- * PxREN: 0 = Pull Up/Down DISABLED, 1 = Pull Up/Down ENABLED
- *
- * PxSEL2 | PxSEL | Explaination
- * 0 | 0 | I/O function selected
- * 0 | 1 | Primary Peripheral module function selected
- * 1 | 0 | Reserved ?
- * 1 | 1 | Secondary Peripheral module function selected
- * [NOTE: P1 and P2 port pin INTs are disabled when PxSEL = 1]
- *
- * PxIFG: 0 = No interrupt pending, 1 = Interrupt Pending
- * PxIES: PxIFG set with a [0 = LOW-HIGH, 1 = HIGH-LOW] transition
- * PxIE : 0 = interrupt disabled, 1 = interrupt enabled
- */
- void handle_port_1 (Emulator *emu)
- {
- Cpu *cpu = emu->cpu;
- Port_1 *p = cpu->p1;
- uint8_t flag = 0;
- //////////////////// P1.0 ////////////////////////
- // Check Direction
- if (*p->_DIR & 0x01) {
- p->DIR_0 = true; // Set P1DIR.0 flag
- if(*p->_OUT & 0x01) {
- if(p->OUT_0 == false) send_control(emu, P1_0_ON_PACKET, NULL, 0);
- p->OUT_0 = true; // Set P1OUT.0 flag
- } else {
- if(p->OUT_0 == true) send_control(emu, P1_0_OFF_PACKET, NULL, 0);
- p->OUT_0 = false;// Reset P1OUT.0 flag
- }
- // if(((p->DIR_0 == false) && (*p->_DIR & 0x01)) || ((*p->_OUT & 0x01) != p->OUT_0)) {
- // if (*p->_OUT & 0x01) send_control(emu, P1_0_ON_PACKET, NULL, 0);
- // else send_control(emu, P1_0_OFF_PACKET, NULL, 0);
- // }
- }
- // Check INPUT
- else {
- p->DIR_0 = false;
- }
-
- /// Check if Interrupt Enabled for pin
- if (*p->_IE & 0x01)
- {
- p->IE_0 = true;
- // Check For Interrupt Pending
- if (*p->_IFG & 0x01)
- {
- // Set p->IFG.0 flag indicating INT
- p->IFG_0 = true;
- }
- else
- {
- p->IFG_0 = false;
- }
- }
- else
- {
- p->IE_0 = false;
- }
- if (*p->_REN & 0x01) p->REN_0 = true;
- else p->REN_0 = false;
-
- // Check primary select
- if (*p->_SEL & 0x01) {
- if (p->SEL_0 == false) {
- // puts("P1_SEL_0 = 1");
- }
-
- p->SEL_0 = true;
- }
- else {
- if (p->SEL_0 == true) {
- // puts("P1_SEL_0 = 0");
- }
- p->SEL_0 = false;
- }
- // Check secondary select
- if (*p->_SEL2 & 0x01) {
- if (p->SEL2_0 == false) {
- // puts("P1_SEL2_0 = 1");
- }
- p->SEL2_0 = true;
- }
- else {
- if (p->SEL2_0 == true) {
- // puts("P1_SEL2_0 = 0");
- }
- p->SEL2_0 = false;
- }
- // if ((p->SEL2_0 == false) && (p->SEL_0 == false)) {
- // // Output
- // if(p->DIR_0 == false) {
- // if(p->OUT_0 == true) flag = P1_0_ON_PACKET;
- // else flag = P1_0_ON_PACKET;
- // // Pull up/down enabled
- // } else if(p->REN_0 == true) {
- // if(p->OUT_0 == true) flag = P1_0_PULLU_PACKET;
- // else flag = P1_0_PULLD_PACKET;
- // } else {
- // flag = P1_0_HIGHZ_PACKET;
- // }
- // if(flag != p->PIN0F) {
- // p->PIN0F = flag;
- // send_control(emu, flag, NULL, 0);
- // }
- // }
- //////////////////// P1.1 ////////////////////////
- // Check Direction and IN/OUT
- if (*p->_DIR & 0x02) {
- p->DIR_1 = true;
- if (*p->_OUT & 0x02) {
- p->OUT_1 = true;
- }
- else {
- p->OUT_1 = false;
- }
- }
- else {
- p->DIR_1 = false;
- }
- // Check Interrupts
- if (*p->_IE & 0x02) {
- p->IE_1 = true;
- if (*p->_IFG & 0x02) {
- p->IFG_1 = true;
- }
- else {
- p->IFG_1 = false;
- }
- }
- else {
- p->IE_1 = false;
- }
- // Check primary select
- if (*p->_SEL & 0x02) {
- if (p->SEL_1 == false) {
- // puts("P1_SEL_1 = 1");
- }
- p->SEL_1 = true;
- }
- else {
- if (p->SEL_1 == true) {
- // puts("P1_SEL_1 = 0");
- }
- p->SEL_1 = false;
- }
- // Check secondary select
- if (*p->_SEL2 & 0x02) {
- if (p->SEL2_1 == false) {
- p->SEL2_1 = true;
- // puts("P1_SEL2_1 = 1");
- }
- }
- else {
- if (p->SEL2_1 == true) {
- p->SEL2_1 = false;
- // puts("P1_SEL2_1 = 0");
- }
- }
- //////////////////// P1.2 ////////////////////////
- if (*p->_DIR & 0x04)
- {
- p->DIR_2 = true;
- if (*p->_OUT & 0x04)
- {
- p->OUT_2 = true;
- }
- else
- {
- p->OUT_2 = false;
- }
- }
- else
- {
- p->DIR_2 = false;
- }
- if (*p->_IE & 0x04)
- {
- p->IE_2 = true;
- if (*p->_IFG & 0x04)
- {
- p->IFG_2 = true;
- }
- else
- {
- p->IFG_2 = false;
- }
- }
- else
- {
- p->IE_2 = false;
- }
- // Check primary select
- if (*p->_SEL & 0x04)
- {
- if (p->SEL_2 == false)
- {
- // puts("P1_SEL_2 = 1");
- }
-
- p->SEL_2 = true;
- }
- else
- {
- if (p->SEL_2 == true)
- {
- // puts("P1_SEL_2 = 0");
- }
- p->SEL_2 = false;
- }
- // Check secondary select
- if (*p->_SEL2 & 0x04) {
- if (p->SEL2_2 == false) {
- // puts("P1_SEL2_2 = 1");
- }
-
- p->SEL2_2 = true;
- }
- else {
- if (p->SEL2_2 == true) {
- // puts("P1_SEL2_2 = 0");
- }
- p->SEL2_2 = false;
- }
- ////////////////////////////////////////////////
- // Handler P1.3
- if (*p->_DIR & 0x08) {
- p->DIR_3 = true;
- if (*p->_OUT & 0x08) {
- p->OUT_3 = true;
- }
- else {
- p->OUT_3 = false;
- }
- }
- else {
- p->DIR_3 = false;
- }
- if (*p->_IE & 0x08) {
- p->IE_3 = true;
- if (*p->_IFG & 0x08) {
- if(!p->IFG_3) service_interrupt(emu, PORT1_VECTOR);
- p->IFG_3 = true;
- }
- else {
- p->IFG_3 = false;
- }
- }
- else {
- p->IE_3 = false;
- }
- if (!p->DIR_3 & p->OUT_3 & p->REN_3) {
- }
- ///////////////////////////////////////////////////////////////
- // Handler P1.4
- if (*p->_DIR & 0x10) {
- p->DIR_4 = true;
- if (*p->_OUT & 0x10) {
- p->OUT_4 = true;
- }
- else {
- p->OUT_4 = false;
- }
- }
- else {
- p->DIR_4 = false;
- }
- if (*p->_IE & 0x10) {
- p->IE_4 = true;
- if (*p->_IFG & 0x10) {
- p->IFG_4 = true;
- }
- else {
- p->IFG_4 = false;
- }
- }
- else {
- p->IE_4 = false;
- }
- /////////////////////////////////////////////////
- // Handler P1.5
- if (*p->_DIR & 0x20) {
- p->DIR_5 = true;
- if (*p->_OUT & 0x20) {
- p->OUT_5 = true;
- }
- else {
- p->OUT_5 = false;
- }
- }
- else {
- p->DIR_5 = false;
- }
- if (*p->_IE & 0x20) {
- p->IE_5 = true;
- if (*p->_IFG & 0x20) {
- p->IFG_5 = true;
- }
- else {
- p->IFG_5 = false;
- }
- }
- else {
- p->IE_5 = false;
- }
- ////////////////////////////////////////////////////
- // Handler P1.6
- if (*p->_DIR & 0x40)
- {
- if(*p->_OUT & 0x40) {
- if(p->OUT_6 == false) send_control(emu, P1_6_ON_PACKET, NULL, 0);
- p->OUT_6 = true; // Set P1OUT.6 flag
- } else {
- if(p->OUT_6 == true) send_control(emu, P1_6_OFF_PACKET, NULL, 0);
- p->OUT_6 = false;// Reset P1OUT.6 flag
- }
- p->DIR_6 = true;
- }
- else
- {
- p->DIR_6 = false;
- }
- if (*p->_IE & 0x40)
- {
- p->IE_6 = true;
- if (*p->_IFG & 0x40)
- {
- p->IFG_6 = true;
- }
- else
- {
- p->IFG_6 = false;
- }
- }
- else
- {
- p->IE_6 = false;
- }
- ////////////////////////////////////////////////////
- // Handler P1.7
- if (*p->_DIR & 0x80) {
- p->DIR_7 = true;
- if (*p->_OUT & 0x80) {
- p->OUT_7 = true;
- }
- else {
- p->OUT_7 = false;
- }
- }
- else {
- p->DIR_7 = false;
- }
- if (*p->_IE & 0x80) {
- p->IE_7 = true;
- if (*p->_IFG & 0x80) {
- p->IFG_7 = true;
- }
- else {
- p->IFG_7 = false;
- }
- }
- else {
- p->IE_7 = false;
- }
- // New P1IN value
- // Natural pull-up configuration
- uint8_t value = (~*p->_DIR) & *p->_REN & *p->_OUT;
- // Pins raised due to external bias
- value |= (p->EXT_EN & p->EXT_DIR);
- // Pins lowered due to external bias
- value &= ~(p->EXT_EN & ~(p->EXT_DIR));
- if(*p->_IN != value) {
- // printf("Changing PIN 0x%02X -> 0x%02X\n", *p->_IN, value);
- // Compute with edge trigger
- uint8_t ifg = *p->_IE & (((~*p->_IN) & value & (~*p->_IES)) | (*p->_IN & (~value) & *p->_IES));
- *p->_IN = value;
- if(ifg > 0 && ifg != *p->_IFG) {
- //printf("Interrupt %02X^%02X %02X\n", ifg, *p->_IFG, (ifg ^ *p->_IFG));
- *p->_IFG |= ifg;
- service_interrupt(emu, PORT1_VECTOR);
- }
- }
- }
- void setup_port_1 (Emulator *emu)
- {
- Cpu *cpu = emu->cpu;
- Port_1 *p = cpu->p1;
-
- static const uint16_t IN_VLOC = 0x20; // Input
- static const uint16_t OUT_VLOC = 0x21; // Output
- static const uint16_t DIR_VLOC = 0x22; // Direction
- static const uint16_t IFG_VLOC = 0x23; // Interrupt flag
- static const uint16_t IES_VLOC = 0x24; // Interrupt Edge Select
- static const uint16_t IE_VLOC = 0x25; // Interrupt Enable
- static const uint16_t SEL_VLOC = 0x26; // Select
- static const uint16_t SEL2_VLOC = 0x41; // Select 2
- static const uint16_t REN_VLOC = 0x27; // Resistor Enable
-
- *(p->_IN = (uint8_t *) get_addr_ptr(IN_VLOC)) = 0;
- *(p->_OUT = (uint8_t *) get_addr_ptr(OUT_VLOC)) = 0;
- *(p->_DIR = (uint8_t *) get_addr_ptr(DIR_VLOC)) = 0;
- *(p->_IFG = (uint8_t *) get_addr_ptr(IFG_VLOC)) = 0;
- *(p->_IES = (uint8_t *) get_addr_ptr(IES_VLOC)) = 0;
- *(p->_IE = (uint8_t *) get_addr_ptr(IE_VLOC)) = 0;
- *(p->_SEL = (uint8_t *) get_addr_ptr(SEL_VLOC)) = 0;
- *(p->_SEL2 = (uint8_t *) get_addr_ptr(SEL2_VLOC)) = 0;
- *(p->_REN = (uint8_t *) get_addr_ptr(REN_VLOC)) = 0;
- p->EXT_EN = 0;
- p->EXT_DIR = 0;
-
- p->DIR_0 = false; p->OUT_0 = false; p->IFG_0 = false;
- p->IE_0 = false; p->SEL_0 = false; p->SEL2_0 = false;
-
- p->DIR_1 = false; p->OUT_1 = false; p->IFG_1 = false;
- p->IE_1 = false; p->SEL_1 = false; p->SEL2_1 = false;
-
- p->DIR_2 = false; p->OUT_2 = false; p->IFG_2 = false;
- p->IE_2 = false; p->SEL_2 = false; p->SEL2_2 = false;
-
- p->DIR_3 = false; p->OUT_3 = false; p->IFG_3 = false;
- p->IE_3 = false; p->SEL_3 = false; p->SEL2_3 = false;
-
- p->DIR_4 = false; p->OUT_4 = false; p->IFG_4 = false;
- p->IE_4 = false; p->SEL_4 = false; p->SEL2_4 = false;
-
- p->DIR_5 = false; p->OUT_5 = false; p->IFG_5 = false;
- p->IE_5 = false; p->SEL_5 = false; p->SEL2_5 = false;
-
- p->DIR_6 = false; p->OUT_6 = false; p->IFG_6 = false;
- p->IE_6 = false; p->SEL_6 = false; p->SEL2_6 = false;
-
- p->DIR_7 = false; p->OUT_7 = false; p->IFG_7 = false;
- p->IE_7 = false; p->SEL_7 = false; p->SEL2_7 = false;
- p->PIN0F = P1_0_OFF_PACKET;
- }
- /* POWER UP CLEAR (PUC)
- *
- * A PUC is always generated when a POR is generated, but a POR is not
- * generated by a PUC. The following events trigger a PUC:
- *
- * A POR signal
- * Watchdog timer expiration when in watchdog mode only
- * Watchdog timer security key violation
- * A Flash memory security key violation
- * A CPU instruct fetch from the peripheral address range 0h to 01FFh
- void power_up_clear () {
- *P1OUT = *P1DIR = *P1IFG = *P1IE = *P1SEL = *P1SEL2 = *P1REN = 0;
- }
- */
|