summaryrefslogtreecommitdiff
path: root/sim/ucsim/stm8.src/flash.cc
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /sim/ucsim/stm8.src/flash.cc
downloadsdcc-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.cc611
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 */