diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /sim/ucsim/stm8.src/flash.cc | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'sim/ucsim/stm8.src/flash.cc')
| -rw-r--r-- | sim/ucsim/stm8.src/flash.cc | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/sim/ucsim/stm8.src/flash.cc b/sim/ucsim/stm8.src/flash.cc new file mode 100644 index 0000000..74e2150 --- /dev/null +++ b/sim/ucsim/stm8.src/flash.cc @@ -0,0 +1,611 @@ +/* + * Simulator of microcontrollers (stm8.src/flash.cc) + * + * Copyright (C) 2017,17 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 <stdlib.h> + +#include "globals.h" + +#include "stm8cl.h" + +#include "flashcl.h" + + +/* Address space/cell which can contain flash memory */ + +t_mem +cl_flash_cell::write(t_mem val) +{ + if (flags & CELL_READ_ONLY) + { + class cl_stm8 *uc= (cl_stm8 *)(application->get_uc()); + if (uc) + { + t_addr a; + if (uc->rom->is_owned(this, &a) && + uc->flash_ctrl) + { + uc->flash_ctrl->flash_write(a, val); + return d(); + } + } + } + return cl_cell8::write(val); +} + +cl_flash_as::cl_flash_as(const char *id, t_addr astart, t_addr asize): + cl_address_space(id, astart, asize, 8) +{ + class cl_flash_cell c8(8); + class cl_memory_cell *cell= &c8; + start_address= astart; + decoders= new cl_decoder_list(2, 2, false); + cella= (class cl_memory_cell *)malloc(size * sizeof(class cl_memory_cell)); + //cell->init(); + int i; + for (i= 0; i < size; i++) + { + void *p= &(cella[i]); + memcpy(p, cell, sizeof(class cl_memory_cell)); + cella[i].init(); + } + dummy= new cl_dummy_cell(8); + dummy->init(); +} + +int +cl_flash_as::init(void) +{ + return cl_address_space::init(); +} + + +/* Flash controller */ + +cl_flash::cl_flash(class cl_uc *auc, t_addr abase, const char *aname): + cl_hw(auc, HW_FLASH, 0, aname) +{ + base= abase; + set_name(aname); + wbuf_started= false; + wbuf_start= 0; + rww= true; +} + +int +cl_flash::init(void) +{ + cl_hw::init(); + registration(); + reset(); + return 0; +} + +char * +cl_flash::cfg_help(t_addr addr) +{ + switch (addr) + { + case stm8_flash_on: return (char*)"Turn simulation of flash on/off (bool, RW)"; + } + return (char*)"Not used"; +} + +int +cl_flash::tick(int cycles) +{ + if (state & fs_busy) + { + double now= uc->get_rtime(); + double elapsed= (now - start_time) * 10e6; + + if ((state == fs_pre_erase) && + (elapsed > tprog/2.0)) + { + int i; + uc->sim->app->debug("FLASH zeroing %06lx .. %d\n", wbuf_start, wbuf_size); + for (i= 0; i < wbuf_size; i++) + { + class cl_memory_cell *c= uc->rom->get_cell(wbuf_start + i); + c->download(0); + } + if (mode == fm_erase) + { + uc->sim->app->debug("FLASH end of erase, finish\n"); + finish_program(true); + } + else + { + uc->sim->app->debug("FLASH end of erase, cont program\n"); + state= fs_program; + } + } + else if (elapsed > tprog) + { + int i; + uc->sim->app->debug("FLASH dl-ing %06lx .. %d\n", wbuf_start, wbuf_size); + for (i= 0; i < wbuf_size; i++) + { + class cl_memory_cell *c= uc->rom->get_cell(wbuf_start + i); + t_mem org= c->get(); + c->download(org | wbuf[i]); + } + uc->sim->app->debug("FLASH end of program\n"); + finish_program(true); + } + } + return 0; +} + +void +cl_flash::finish_program(bool ok) +{ + if (ok) + iapsr->set_bit1(0x04); + else + iapsr->set_bit1(0x01); + state= fs_wait_mode; +} + +void +cl_flash::reset(void) +{ + uc->sim->app->debug("FLASH reset\n"); + puk1st= false; + duk1st= false; + p_unlocked= false; + d_unlocked= false; + p_failed= false; + d_failed= false; + + state= fs_wait_mode; + mode= fm_unknown; + + cr1r->write(0); + iapsr->write(0x40); + cr2r->write(0); + if (ncr2r) + ncr2r->write(0xff); +} + +t_mem +cl_flash::read(class cl_memory_cell *cell) +{ + t_mem v= cell->get(); + + if (cell == pukr) + v= 0; + else if (cell == dukr) + v= 0; + else if (cell == iapsr) + { + v&= ~0x0a; + if (p_unlocked) + v|= 0x02; + if (d_unlocked) + v|= 0x08; + // read clears EOP and WR_PG_DIS bits + cell->set(v & ~0x05); + if (v & 0x05) uc->sim->app->debug("FLASH read iapsr5 %02x\n",v); + } + return v; +} + +void +cl_flash::write(class cl_memory_cell *cell, t_mem *val) +{ + if (conf(cell, val)) + return; + + if (conf(cell, NULL)) + return; + + if (cell == pukr) + { + uc->sim->app->debug("FLASH write-pukr %02x\n",*val); + if (p_failed) + ; + else if (!puk1st) + { + if (*val == PMASS1) + puk1st= true; + else + p_failed= true; + } + else + { + if (*val == PMASS2) + puk1st= false, p_unlocked= true; + else + puk1st= false, p_failed= true; + } + *val= 0; + } + else if (cell == dukr) + { + uc->sim->app->debug("FLASH write-dukr %02x\n",*val); + if (d_failed) + ; + else if (!duk1st) + { + if (*val == DMASS1) + duk1st= true; + else + d_failed= true; + } + else + { + if (*val == DMASS2) + duk1st= false, d_unlocked= true; + else + duk1st= false, d_failed= true; + } + *val= 0; + } + else if (cell == iapsr) + { + uc->sim->app->debug("FLASH write-iapsr %02x\n",*val); + t_mem org= iapsr->get(); + // PUL, DUL + if (!(*val & 0x02)) + p_unlocked= puk1st= false; + if (!(*val & 0x08)) + d_unlocked= duk1st= false; + *val&= ~0x0a; + if (p_unlocked) + *val|= 0x02; + if (d_unlocked) + *val|= 0x08; + // HVOFF + *val&= ~0x40; + // EOP + *val&= 0x40; + if (org & 0x40) + *val|= 0x40; + } + else if (cell == cr2r) + { + uc->sim->app->debug("FLASH write-cr2r %02x\n",*val); + *val&= ~0x0e; + if (state & fs_busy) + { + *val&= ~0x30; + *val|= (cr2r->get() & 0x30); + } + if ((ncr2r == NULL) || + (ncr2r->get() == ((~(*val))&0xff))) + set_flash_mode(*val); + } + else if ((ncr2r != NULL) && + (cell == ncr2r)) + { + uc->sim->app->debug("FLASH write-ncr2r %02x\n",*val); + *val|= 0x0e; + if (state & fs_busy) + { + *val&= ~0x30; + *val|= (ncr2r->get() & 0x30); + } + if (cr2r->get() == ((~(*val))&0xff)) + set_flash_mode((~(*val))&0xff); + } +} + +t_mem +cl_flash::conf_op(cl_memory_cell *cell, t_addr addr, t_mem *val) +{ + switch ((enum stm8_flash_cfg)addr) + { + case stm8_flash_on: + if (val) + { + if (*val) + on= true; + else + on= false; + } + else + cell->set(on?1:0); + break; + case stm8_flash_nuof_cfg: + break; + } + return cell->get(); +} + +void +cl_flash::flash_write(t_addr a, t_mem val) +{ + uc->sim->app->debug("FLASH wr(%06lx,%02x)\n",a,val); + if (!uc) + { + uc->sim->app->debug(" no uc\n"); + return; + } + if (uc->rom == NULL) + { + uc->sim->app->debug(" no rom\n"); + return; + } + if ((a >= 0x8000) && + !p_unlocked) + { + uc->sim->app->debug(" plocked\n"); + return; + } + if ((a < 0x8000) && + !d_unlocked) + { + uc->sim->app->debug(" dlocked\n"); + return; + } + if (state & fs_busy) + { + uc->sim->app->debug(" busy %d\n",state); + return; + } + + uc->sim->app->debug(" wbuf_start=%06lx\n",wbuf_start); + if (wbuf_start == 0) + { + uc->sim->app->debug(" calling start_wbuf(%06lx)\n",a); + start_wbuf(a); + } + + int offset= a - wbuf_start; + uc->sim->app->debug(" offset=%d\n",offset); + if (mode == fm_byte) + { + // fixup tprog + wbuf[0]= uc->rom->get(wbuf_start + 0); + wbuf[1]= uc->rom->get(wbuf_start + 1); + wbuf[2]= uc->rom->get(wbuf_start + 2); + wbuf[3]= uc->rom->get(wbuf_start + 3); + if (tprog < 6000) + { + if (wbuf[0] || + wbuf[1] || + wbuf[2] || + wbuf[3]) + tprog= 6000; + } + wbuf[offset]= val; + if (tprog < 6000) + start_program(fs_program); + } + else if (mode == fm_erase) + { + uc->sim->app->debug(" romwrite in erase mode\n"); + wbuf[offset]= val; + wbuf_writes++; + if ((wbuf_writes == 4) && + (((a+1) % 4) == 0)) + { + u8_t v= 0; + v|= wbuf[0]; + v|= wbuf[1]; + v|= wbuf[2]; + v|= wbuf[3]; + if (v == 0) + { + uc->sim->app->debug(" starting erase\n"); + start_program(fs_pre_erase); + } + } + } + else + { + wbuf[offset]= val; + wbuf_started= true; + wbuf_writes++; + if ((wbuf_writes == wbuf_size) || + (offset == wbuf_size-1)) + { + if ((mode == fm_fast_word) || + (mode == fm_fast_block)) + start_program(fs_program); + else + start_program(fs_pre_erase); + } + } +} + +// normal program: 6 ms +// fast program: 3 ms +// erase: 3 ms + +void +cl_flash::set_flash_mode(t_mem cr2val) +{ + bool fix= cr1r->get() & 0x01; /* FIX */ + + uc->sim->app->debug("FLASH set_mode %02x\n", cr2val); + if (cr2val & 0x40 /* WPRG */ ) + { + mode= fm_word; + tprog= 6000; /* normal mode */ + wbuf_size= 4; + } + else if (cr2val & 0x20 /* ERASE */ ) + { + mode= fm_erase; + tprog= 3000; + wbuf_size= 128; + } + else if (cr2val & 0x10 /* FPRG */ ) + { + mode= fm_fast_block; + tprog= 3000; + wbuf_size= 128; + } + else if (cr2val & 0x01 /* PRG */ ) + { + mode= fm_block; + tprog= 6000; + wbuf_size= 128; + } + else + { + mode= fm_byte; + tprog= fix?6000:3000; + wbuf_size= 4; + } + state= fs_wait_data; + wbuf_started= false; + wbuf_start= 0; +} + +void +cl_flash::start_wbuf(t_addr addr) +{ + int i; + wbuf_start= addr - (addr % wbuf_size); + wbuf_writes= 0; + for (i= 0; i < 256; i++) + wbuf[i]= 0; + uc->sim->app->debug("FLASH start_wbuf %06lx (wbuf_start=%06lx,size=%d)\n", addr, wbuf_start, wbuf_size); +} + +void +cl_flash::start_program(enum stm8_flash_state start_state) +{ + uc->sim->app->debug("FLASH start prg %d\n", start_state); + state= start_state; + start_time= uc->get_rtime(); +} + +const char * +cl_flash::state_name(enum stm8_flash_state s) +{ + switch (s) + { + case fs_wait_mode: return "wait_mode"; + case fs_wait_data: return "wait_data"; + case fs_pre_erase: return "erase"; + case fs_program: return "program"; + case fs_busy: return "busy"; + } + return "unknown"; +} + +void +cl_flash::print_info(class cl_console_base *con) +{ + con->dd_printf(chars("", "Flash at %s\n", uc->rom->addr_format), base); + con->dd_printf("PUK: "); + if (p_failed) + con->dd_printf("fail"); + else if (p_unlocked) + con->dd_printf("unlocked"); + else if (puk1st) + con->dd_printf("MASS1"); + else + con->dd_printf("locked"); + con->dd_printf("\n"); + + con->dd_printf("DUK: "); + if (d_failed) + con->dd_printf("fail"); + else if (d_unlocked) + con->dd_printf("unlocked"); + else if (duk1st) + con->dd_printf("MASS1"); + else + con->dd_printf("locked"); + con->dd_printf("\n"); + + con->dd_printf("State: %s\n", state_name(state)); + print_cfg_info(con); +} + + +/* SAF */ + +cl_saf_flash::cl_saf_flash(class cl_uc *auc, t_addr abase): + cl_flash(auc, abase, "flash") +{ +} + +void +cl_saf_flash::registration(void) +{ + class cl_it_src *is; + + cr1r= register_cell(uc->rom, base+0); + cr2r= register_cell(uc->rom, base+1); + ncr2r= register_cell(uc->rom, base+2); + iapsr= register_cell(uc->rom, base+5); + pukr= register_cell(uc->rom, base+8); + dukr= register_cell(uc->rom, base+10); + + uc->it_sources->add(is= new cl_it_src(uc, 24, + cr1r,0x02, + iapsr,0x04, + 0x8008+24*4, false, false, + chars("end of flash programming"), 20*20+0)); + uc->it_sources->add(is= new cl_it_src(uc, 24, + cr1r,0x02, + iapsr,0x01, + 0x8008+24*4, false, false, + chars("write attempted to protected page"), 20*20+1)); + is->init(); +} + + +/* L,L101 */ + +cl_l_flash::cl_l_flash(class cl_uc *auc, t_addr abase): + cl_flash(auc, abase, "flash") +{ +} + +void +cl_l_flash::registration(void) +{ + class cl_it_src *is; + + cr1r= register_cell(uc->rom, base+0); + cr2r= register_cell(uc->rom, base+1); + pukr= register_cell(uc->rom, base+2); + dukr= register_cell(uc->rom, base+3); + iapsr= register_cell(uc->rom, base+4); + ncr2r= NULL; + + uc->it_sources->add(is= new cl_it_src(uc, 1, + cr1r,0x02, + iapsr,0x04, + 0x8008+1*4, false, false, + chars("end of flash programming"), 20*20+0)); + uc->it_sources->add(is= new cl_it_src(uc, 1, + cr1r,0x02, + iapsr,0x01, + 0x8008+1*4, false, false, + chars("write attempted to protected page"), 20*20+1)); + is->init(); +} + + +/* End of stm8.src/flash.cc */ |
