/* * Simulator of microcontrollers (pca.cc) * * Copyright (C) 1999,99 Drotos Daniel, Talker Bt. * * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu * */ /* This file is part of microcontroller simulator: ucsim. UCSIM 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 2 of the License, or (at your option) any later version. UCSIM 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 UCSIM; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*@1@*/ #include // sim.src #include "itsrccl.h" // local #include "pcacl.h" #include "regs51.h" #include "types51.h" cl_pca::cl_pca(class cl_uc *auc, int aid): cl_hw(auc, HW_PCA, aid, "pca") { t0_overflows= ECI_edge= 0; int i; for (i= 0; i < 5; cex_pos[i]= cex_neg[i]= false, i++) ; } int cl_pca::init(void) { cl_hw::init(); sfr= uc->address_space(MEM_SFR_ID); //t_addr CCAPL[5]= {CCAPL[0], CCAPL[1], CCAPL[2], CCAPL[3], CCAPL[4]}; //t_addr CCAPH[5]= {CCAPH[0], CCAPH[1], CCAPH[2], CCAPH[3], CCAPH[4]}; //t_addr CCAPM[5]= {CCAPM[0], CCAPM[1], CCAPM[2], CCAPM[3], CCAPM[4]}; t_addr CCAPL[5]= {CCAP0L, CCAP1L, CCAP2L, CCAP3L, CCAP4L}; t_addr CCAPH[5]= {CCAP0H, CCAP1H, CCAP2H, CCAP3H, CCAP4H}; t_addr CCAPM[5]= {CCAPM0, CCAPM1, CCAPM2, CCAPM3, CCAPM4}; int i; if (!sfr) { fprintf(stderr, "No SFR to register PCA[%d] into\n", id); } cell_cmod= register_cell(sfr, CMOD); cell_ccon= register_cell(sfr, CCON); for (i= 0; i < 5; i++) { cell_ccapl[i]= sfr->get_cell(CCAPL[i]);//use_cell(sfr, CCAPL[i]); cell_ccaph[i]= sfr->get_cell(CCAPH[i]);//use_cell(sfr, CCAPH[i]); cell_ccapm[i]= register_cell(sfr, CCAPM[i]); } cell_cl= sfr->get_cell(CL);//use_cell(sfr, CL); cell_ch= sfr->get_cell(CH);//use_cell(sfr, CH); cl_address_space *bas= uc->address_space("bits"); cell_cr= register_cell(bas, 0xda); return(0); } void cl_pca::added_to_uc(void) { class cl_address_space *sfr= uc->address_space(MEM_SFR_ID); class cl_it_src *is; uc->it_sources->add_at(4, is= new cl_it_src(uc, bmEC, sfr->get_cell(IE), bmEC, sfr->get_cell(CCON), bmCCF4, 0x0033, false, false, "PCA module #4", 5)); is->init(); uc->it_sources->add_at(4, is= new cl_it_src(uc, bmEC, sfr->get_cell(IE), bmEC, sfr->get_cell(CCON), bmCCF3, 0x0033, false, false, "PCA module #3", 5)); is->init(); uc->it_sources->add_at(4, is= new cl_it_src(uc, bmEC, sfr->get_cell(IE), bmEC, sfr->get_cell(CCON), bmCCF2, 0x0033, false, false, "PCA module #2", 5)); is->init(); uc->it_sources->add_at(4, is= new cl_it_src(uc, bmEC, sfr->get_cell(IE), bmEC, sfr->get_cell(CCON), bmCCF1, 0x0033, false, false, "PCA module #1", 5)); is->init(); uc->it_sources->add_at(4, is= new cl_it_src(uc, bmEC, sfr->get_cell(IE), bmEC, sfr->get_cell(CCON), bmCCF0, 0x0033, false, false, "PCA module #0", 5)); is->init(); uc->it_sources->add_at(4, is= new cl_it_src(uc, bmEC, sfr->get_cell(IE), bmEC, sfr->get_cell(CCON), bmCF, 0x0033, false, false, "PCA counter", 5)); is->init(); } void cl_pca::write(class cl_memory_cell *cell, t_mem *val) { //uchar bmCEX[5]= {bmCEX0, bmCEX1, bmCEX2, bmCEX3, bmCEX4}; //uchar bmCCF[5]= {bmCCF0, bmCCF1, bmCCF2, bmCCF3, bmCCF4}; if (cell == cell_cmod) { bit_CIDL= *val & bmCIDL; bit_WDTE= *val & bmWDTE; bit_ECF = *val & bmECF; t_mem o= clk_source; if ((clk_source= *val & (bmCPS1|bmCPS0)) != o) t0_overflows= ECI_edge= 0; } else if (cell == cell_ccon) { bit_CR= *val & bmCR; } else if (cell == cell_cr) { bit_CR= *val; } else { int i; for (i= 0; i < 5; i++) { if (cell == cell_ccapm[i]) { t_mem o= ccapm[i]; ccapm[i]= *val & 0xff; if (o != ccapm[i]) cex_neg[i]= cex_pos[i]= false; } else { if (ccapm[i] & (bmMAT|bmTOG)) { if (cell == cell_ccapl[i]) { cell_ccapm[i]->set_bit0(bmECOM); ccapm[i]= cell_ccapm[i]->get(); } else if (cell == cell_ccaph[i]) { cell_ccapm[i]->set_bit1(bmECOM); ccapm[i]= cell_ccapm[i]->get(); } } } } } } /*void cl_pca::mem_cell_changed(class cl_m *mem, t_addr addr) { class cl_m *sfr= uc->mem(MEM_SFR); if (mem && sfr && mem == sfr) { if (addr == addr_ccapXl) ccapXl= sfr->get_cell(addr_ccapXl); else if (addr == addr_ccapXh) ccapXh= sfr->get_cell(addr_ccapXh); else if (addr == addr_ccapmX) ccapmX= sfr->get_cell(addr_ccapmX); } }*/ int cl_pca::tick(int cycles) { int ret= resGO; if (!bit_CR) return(resGO); if (uc->state == stIDLE && bit_CIDL) return(resGO); switch (clk_source) { case 0: do_pca_counter(cycles); break; case bmCPS0: do_pca_counter(cycles*3); break; case bmCPS1: do_pca_counter(t0_overflows); t0_overflows= 0; break; case (bmCPS0|bmCPS1): do_pca_counter(ECI_edge); ECI_edge= 0; break; } return(ret); } void cl_pca::do_pca_counter(int cycles) { //class cl_m *sfr= uc->mem(MEM_SFR); while (cycles--) { if (cell_cl->add(1) == 0) { int i; for (i= 0; i < 5; i++) if (ccapm[i] & bmPWM) cell_ccapl[i]->set(cell_ccaph[i]->get()); if (cell_ch->add(1) == 0) { // CH,CL overflow cell_ccon->set_bit1(bmCF); do_pca_module(0); do_pca_module(1); do_pca_module(2); do_pca_module(3); do_pca_module(4); } } } } void cl_pca::do_pca_module(int nr) { uchar bmCEX[5]= {bmCEX0, bmCEX1, bmCEX2, bmCEX3, bmCEX4}; uchar bmCCF[5]= {bmCCF0, bmCCF1, bmCCF2, bmCCF3, bmCCF4}; //uint p1= sfr->get(P1); bool capture= false; if ((ccapm[nr] & bmCAPP) && cex_pos[nr]) { capture= true; cex_pos[nr]= false; } if ((ccapm[nr] & bmCAPN) && cex_neg[nr]) { capture= true; cex_pos[nr]= false; } if (capture) { // Capture cell_ccapl[nr]->set(cell_cl->get()); cell_ccaph[nr]->set(cell_ch->get()); cell_ccon->set_bit1(bmCCF[nr]); } if (ccapm[nr] & bmECOM) { // Comparator enabled if (cell_cl->get() == cell_ccapl[nr]->get() && cell_ch->get() == cell_ccaph[nr]->get()) { // Match if (nr == 4 && (bit_WDTE)) { reset(); return; } cell_ccon->set_bit1(bmCCF[nr]); if (ccapm[nr] & bmTOG) { // Toggle sfr->set(P1, sfr->get(P1) ^ bmCEX[nr]); } } if (ccapm[nr] & bmPWM) { // PWM /*if (cell_cl->get() == 0) cell_ccapl[nr]->set(cell_ccaph[nr]->get());*/ if (cell_cl->get() < cell_ccapl[nr]->get()) //sfr->set(P1, sfr->get(P1) & ~(bmCEX[nr])); sfr->set_bit1(P1, bmCEX[nr]); else sfr->set_bit1(P1, bmCEX[nr]); } } } void cl_pca::reset(void) { t0_overflows= ECI_edge= 0; int i; for (i= 0; i < 5; cex_pos[i]= cex_neg[i]= false, i++) ; } void cl_pca::happen(class cl_hw *where, enum hw_event he, void *params) { struct ev_port_changed *ep= (struct ev_port_changed *)params; uchar bmCEX[5]= {bmCEX0, bmCEX1, bmCEX2, bmCEX3, bmCEX4}; if (where->cathegory == HW_PORT && he == EV_PORT_CHANGED && ep->id == 1) { t_mem p1n= ep->new_pins & ep->new_value; t_mem p1o= ep->pins & ep->prev_value; if (!(p1n & bmECI) && (p1o & bmECI)) ECI_edge++; int i; for (i= 0; i < 5; i++) { if (!(p1n & bmCEX[i]) && (p1o & bmCEX[i])) cex_neg[i]= true; else if ((p1n & bmCEX[i]) && !(p1o & bmCEX[i])) cex_pos[i]= true; } } else if (where->cathegory == HW_TIMER && he == EV_OVERFLOW && where->id == 0) { t0_overflows++; } } void cl_pca::print_info(class cl_console_base *con) { con->dd_printf("%s[%d] FIXME\n", id_string, id); print_cfg_info(con); } /* End of s51.src/pca.cc */