/* * Simulator of microcontrollers (arith_inst.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 "avrcl.h" #include "regsavr.h" /* * Compare with Immediate * CPI Rd,K 16<=d<=31, 0<=K<=255 * 0011 KKKK dddd KKKK *____________________________________________________________________________ */ int cl_avr::cpi_Rd_K(t_mem code) { t_addr d; t_mem D, K, result, res; d= 16+((code&0xf0)>>4); K= (code&0xf) | ((code&0xf00)>>8); D= ram->read(d); if (K & 0x80) K|= ~0xff; if (D & 0x80) D|= ~0xff; t_mem sreg= ram->get(SREG); result= (signed)D-(signed)K; res= result & 0xff; sreg= sreg & ~(BIT_H|BIT_S|BIT_V|BIT_N|BIT_C|BIT_Z); if (0x08 & (((~D)&K) | (K&res) | (res&(~D)))) sreg|= BIT_H; int n= 0, v= 0; if (0x80 & ((D&(~K)&(~res)) | ((~D)&K&res))) { sreg|= BIT_V; v= 1; } if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (!res) sreg|= BIT_Z; if (0x80 & (((~D)&K) | (K&res) | (res&(~D)))) sreg|= BIT_C; ram->set(SREG, sreg); return(resGO); } /* * Substract Immediate with Carry * SBCI Rd,K 16<=d<=31, 0<=K<=255 * 0100 KKKK dddd KKKK *____________________________________________________________________________ */ int cl_avr::sbci_Rd_K(t_mem code) { t_addr d; t_mem D, K, result, res; d= 16+((code&0xf0)>>4); K= (code&0xf) | ((code&0xf00)>>8); D= ram->read(d); if (K & 0x80) K|= ~0xff; if (D & 0x80) D|= ~0xff; t_mem sreg= ram->get(SREG); result= (signed)D-(signed)K-(sreg&BIT_C)?1:0; res= result & 0xff; ram->write(d, res); sreg= sreg & ~(BIT_H|BIT_S|BIT_V|BIT_N|BIT_C); if (0x08 & (((~D)&K) | (K&res) | (res&(~D)))) sreg|= BIT_H; int n= 0, v= 0; if (0x80 & ((D&(~K)&(~res)) | ((~D)&K&res))) { sreg|= BIT_V; v= 1; } if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (res) sreg&= ~BIT_Z; if (0x80 & (((~D)&K) | (K&res) | (res&(~D)))) sreg|= BIT_C; ram->set(SREG, sreg); return(resGO); } /* * Substract Immediate * SUBI Rd,K 16<=d<=31, 0<=K<=255 * 0101 KKKK dddd KKKK *____________________________________________________________________________ */ int cl_avr::subi_Rd_K(t_mem code) { t_addr d; t_mem D, K, result, res; d= 16+((code&0xf0)>>4); K= (code&0xf) | ((code&0xf00)>>8); D= ram->read(d); if (K & 0x80) K|= ~0xff; if (D & 0x80) D|= ~0xff; result= (signed)D-(signed)K; res= result & 0xff; ram->write(d, res); t_mem sreg= ram->get(SREG) & ~(BIT_H|BIT_S|BIT_V|BIT_N|BIT_Z|BIT_C); if (0x08 & (((~D)&K) | (K&res) | (res&(~D)))) sreg|= BIT_H; int n= 0, v= 0; if (0x80 & ((D&(~K)&(~res)) | ((~D)&K&res))) { sreg|= BIT_V; v= 1; } if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (!res) sreg|= BIT_Z; if (0x80 & (((~D)&K) | (K&res) | (res&(~D)))) sreg|= BIT_C; ram->set(SREG, sreg); return(resGO); } int cl_avr::muls_Rd_Rr(t_mem code) { return(resGO); } int cl_avr::mulsu_Rd_Rr(t_mem code) { return(resGO); } int cl_avr::fmul_Rd_Rr(t_mem code) { return(resGO); } int cl_avr::fmuls_Rd_Rr(t_mem code) { return(resGO); } int cl_avr::fmulsu_Rd_Rr(t_mem code) { return(resGO); } /* * Compare with Carry * CPC Rd,Rr 0<=d<=31, 0<=r<=31 * 0000 01rd dddd rrrr *____________________________________________________________________________ */ int cl_avr::cpc_Rd_Rr(t_mem code) { t_addr r, d; t_mem R, D, result, res; d= (code&0x1f0)>>4; r= ((code&0x200)>>5)|(code&0xf); R= ram->read(r); D= ram->read(d); if (R & 0x80) R|= ~0xff; if (D & 0x80) D|= ~0xff; t_mem sreg= ram->get(SREG); result= (signed)D-(signed)R-(sreg&BIT_C)?1:0; res= result & 0xff; sreg= sreg & ~(BIT_H|BIT_S|BIT_V|BIT_N|BIT_C); if (0x08 & (((~D)&R) | (R&res) | (res&(~D)))) sreg|= BIT_H; int n= 0, v= 0; if (0x80 & ((D&(~R)&(~res)) | ((~D)&R&res))) { sreg|= BIT_V; v= 1; } if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (res) sreg&= ~BIT_Z; if (0x80 & (((~D)&R) | (R&res) | (res&(~D)))) sreg|= BIT_C; ram->set(SREG, sreg); return(resGO); } /* * Substract with Carry * SBC Rd,Rr 0<=d<=31, 0<=r<=31 * 0000 10rd dddd rrrr *____________________________________________________________________________ */ int cl_avr::sbc_Rd_Rr(t_mem code) { t_addr r, d; t_mem R, D, result, res; d= (code&0x1f0)>>4; r= ((code&0x200)>>5)|(code&0xf); R= ram->read(r); D= ram->read(d); if (R & 0x80) R|= ~0xff; if (D & 0x80) D|= ~0xff; t_mem sreg= ram->get(SREG); result= (signed)D-(signed)R-(sreg&BIT_C)?1:0; res= result & 0xff; ram->write(d, res); sreg= sreg & ~(BIT_H|BIT_S|BIT_V|BIT_N|BIT_C); if (0x08 & (((~D)&R) | (R&res) | (res&(~D)))) sreg|= BIT_H; int n= 0, v= 0; if (0x80 & ((D&(~R)&(~res)) | ((~D)&R&res))) { sreg|= BIT_V; v= 1; } if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (res) sreg&= ~BIT_Z; if (0x80 & (((~D)&R) | (R&res) | (res&(~D)))) sreg|= BIT_C; ram->set(SREG, sreg); return(resGO); } /* * Add without Carry * ADD Rd,Rr 0<=d<=31, 0<=r<=31 * 0000 11rd dddd rrrr *____________________________________________________________________________ */ int cl_avr::add_Rd_Rr(t_mem code) { t_addr r, d; t_mem R, D, result, res; d= (code&0x1f0)>>4; r= ((code&0x200)>>5)|(code&0xf); R= ram->read(r); D= ram->read(d); result= D+R; res= result & 0xff; ram->write(d, res); t_mem sreg= ram->get(SREG); if (!res) sreg|= BIT_Z; else sreg&= ~BIT_Z; if (((D&R&~res)&0x80) || ((~D&~R&res)&0x80)) sreg|= (BIT_V|BIT_S); else sreg&= ~(BIT_V|BIT_S); if (res & 0x80) { sreg|= BIT_N; sreg^= BIT_S; } else sreg&= ~BIT_N; if (result & ~0xff) sreg|= BIT_C; else sreg&= ~BIT_C; if ((R&0xf) + (D&0xf) > 15) sreg|= BIT_H; else sreg&= ~BIT_H; ram->set(SREG, sreg); return(resGO); } /* * Compare * CP Rd,Rr 0<=d<=31, 0<=r<=31 * 0001 01rd dddd rrrr *____________________________________________________________________________ */ int cl_avr::cp_Rd_Rr(t_mem code) { t_addr r, d; t_mem R, D, result, res; d= (code&0x1f0)>>4; r= ((code&0x200)>>5)|(code&0xf); R= ram->read(r); D= ram->read(d); if (R & 0x80) R|= ~0xff; if (D & 0x80) D|= ~0xff; result= (signed)D-(signed)R; res= result & 0xff; t_mem sreg= ram->get(SREG) & ~(BIT_H|BIT_S|BIT_V|BIT_N|BIT_Z|BIT_C); if (0x08 & (((~D)&R) | (R&res) | (res&(~D)))) sreg|= BIT_H; int n= 0, v= 0; if (0x80 & ((D&(~R)&(~res)) | ((~D)&R&res))) { sreg|= BIT_V; v= 1; } if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (!res) sreg|= BIT_Z; if (0x80 & (((~D)&R) | (R&res) | (res&(~D)))) sreg|= BIT_C; ram->set(SREG, sreg); return(resGO); } /* * Substract without Carry * SUB Rd,Rr 0<=d<=31, 0<=r<=31 * 0001 10rd dddd rrrr *____________________________________________________________________________ */ int cl_avr::sub_Rd_Rr(t_mem code) { t_addr r, d; t_mem R, D, result, res; d= (code&0x1f0)>>4; r= ((code&0x200)>>5)|(code&0xf); R= ram->read(r); D= ram->read(d); if (R & 0x80) R|= ~0xff; if (D & 0x80) D|= ~0xff; result= (signed)D-(signed)R; res= result & 0xff; ram->write(d, res); t_mem sreg= ram->get(SREG) & ~(BIT_H|BIT_S|BIT_V|BIT_N|BIT_Z|BIT_C); if (0x08 & (((~D)&R) | (R&res) | (res&(~D)))) sreg|= BIT_H; int n= 0, v= 0; if (0x80 & ((D&(~R)&(~res)) | ((~D)&R&res))) { sreg|= BIT_V; v= 1; } if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (!res) sreg|= BIT_Z; if (0x80 & (((~D)&R) | (R&res) | (res&(~D)))) sreg|= BIT_C; ram->set(SREG, sreg); return(resGO); } /* * Add with Carry * ADC Rd,Rr 0<=d<=31, 0<=r<=31 * 0001 11rd dddd rrrr *____________________________________________________________________________ */ int cl_avr::adc_Rd_Rr(t_mem code) { t_addr r, d; t_mem R, D, result, res; d= (code&0x1f0)>>4; r= ((code&0x200)>>5)|(code&0xf); R= ram->read(r); D= ram->read(d); t_mem sreg= ram->get(SREG); result= D+R+((sreg&BIT_C)?1:0); res= result & 0xff; ram->write(d, res); if (!res) sreg|= BIT_Z; else sreg&= ~BIT_Z; if (((D&R&~res)&0x80) || ((~D&~R&res)&0x80)) sreg|= (BIT_V|BIT_S); else sreg&= ~(BIT_V|BIT_S); if (res & 0x80) { sreg|= BIT_N; sreg^= BIT_S; } else sreg&= ~BIT_N; if (result & ~0xff) sreg|= BIT_C; else sreg&= ~BIT_C; if ((R&0xf) + (D&0xf) > 15) sreg|= BIT_H; else sreg&= ~BIT_H; ram->set(SREG, sreg); return(resGO); } /* * One's Complement * COM Rd 0<=d<=31 * 1001 010d dddd 0000 *____________________________________________________________________________ */ int cl_avr::com_Rd(t_mem code) { t_addr d; t_mem D, result, res; d= (code&0x1f0)>>4; D= ram->read(d); result= ~D; res= result & 0xff; ram->write(d, res); t_mem sreg= ram->get(SREG); if (!res) sreg|= BIT_Z; else sreg&= ~BIT_Z; sreg&= ~BIT_V; if (res & 0x80) sreg|= (BIT_N|BIT_S); else sreg&= ~(BIT_N|BIT_S); sreg|= BIT_C; ram->set(SREG, sreg); return(resGO); } /* * Two's Complement * NEG Rd 0<=d<=31 * 1001 010d dddd 0001 *____________________________________________________________________________ */ int cl_avr::neg_Rd(t_mem code) { t_addr d; t_mem D, result, res; d= (code&0x1f0)>>4; D= ram->read(d); result= (~D)+1; res= result & 0xff; ram->write(d, res); t_mem sreg= ram->get(SREG); if (res & (~d) & 0x08) sreg|= BIT_H; else sreg&= ~BIT_H; if (res > 0x80) sreg|= BIT_S; else sreg&= ~BIT_S; if (!res) { sreg|= BIT_Z; sreg&= ~BIT_C; } else { sreg&= ~BIT_Z; sreg|= BIT_C; } if (res == 0x80) sreg|= BIT_V; else sreg&= ~BIT_V; if (res & 0x80) sreg|= (BIT_N); else sreg&= ~BIT_N; ram->set(SREG, sreg); return(resGO); } /* * Increment * INC Rd 0<=d<=31 * 1001 010d dddd 0011 *____________________________________________________________________________ */ int cl_avr::inc_Rd(t_mem code) { t_addr d; d= (code&0x1f0)>>4; t_mem data= ram->read(d)+1; ram->write(d, data); t_mem sreg= ram->get(SREG); data= data&0xff; if (data & 0x80) { sreg|= (BIT_N); if (data == 0x80) { sreg|= BIT_V; sreg&= ~BIT_S; } else { sreg&= ~BIT_V; sreg|= BIT_S; } sreg&= ~BIT_Z; } else { sreg&= ~(BIT_N|BIT_V|BIT_S); if (!data) sreg|= BIT_Z; else sreg&= ~BIT_Z; } ram->set(SREG, sreg); return(resGO); } /* * Arithmetic Shift Right * ASR Rd 0<=d<=31 * 1001 010d dddd 0101 *____________________________________________________________________________ */ int cl_avr::asr_Rd(t_mem code) { t_addr d; t_mem D, result, res; d= (code&0x1f0)>>4; D= ram->read(d); t_mem sreg= ram->read(SREG) & ~(BIT_S|BIT_V|BIT_N|BIT_Z|BIT_C); int n=0, v= 0, c= 0; if (D & 1) { sreg|= BIT_C; c= 1; } result= D>>1; if (result & 0x40) result|= 0x80; res= result & 0xff; ram->write(d, res); if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ c) & 1) { sreg|= BIT_V; v= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (!res) sreg|= BIT_Z; ram->write(SREG, sreg); return(resGO); } /* * Logical Shift Right * LSR Rd 0<=d<=31 * 1001 010d dddd 0110 *____________________________________________________________________________ */ int cl_avr::lsr_Rd(t_mem code) { t_addr d; t_mem D, result, res; d= (code &0x1f0)>>4; D= ram->read(d); t_mem sreg= ram->read(SREG) & ~(BIT_S|BIT_V|BIT_N|BIT_Z|BIT_C); if (D & 1) sreg|= (BIT_C|BIT_V|BIT_S); result= D >> 1; res= result & 0xff; ram->write(d, res); if (!res) sreg|= BIT_Z; ram->write(SREG, sreg); return(resGO); } /* * Rotate Right trough Carry * ROR Rd 0<=d<=31 * 1001 010d dddd 0111 *____________________________________________________________________________ */ int cl_avr::ror_Rd(t_mem code) { t_addr d; t_mem D, result, res; d= (code&0x1f0)>>4; D= ram->read(d); t_mem sreg= ram->read(SREG); int oldc= sreg & BIT_C; sreg= sreg & ~(BIT_S|BIT_V|BIT_N|BIT_Z|BIT_C); int n= 0, v= 0, c= 0; if (D & 1) { sreg|= BIT_C; c= 1; } result= (D >> 1) | oldc?0x80:0; res= result & 0xff; ram->write(d, res); if (res & 0x80) { sreg|= BIT_N; n= 1; } if ((n ^ c) & 1) { sreg|= BIT_V; v= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (!res) sreg|= BIT_Z; ram->write(SREG, sreg); return(resGO); } /* * Decrement * DEC Rd 0<=d<=31 * 1001 010d dddd 1010 *____________________________________________________________________________ */ int cl_avr::dec_Rd(t_mem code) { t_addr d; t_mem D, result, res; d= (code&0x1f0)>>4; D= ram->read(d); result= D-1; res= result & 0xff; ram->write(d, res); t_mem sreg= ram->get(SREG); if (!res) sreg|= BIT_Z; else sreg&= ~BIT_Z; int n= 0, v= 0; if (res & 0x80) { sreg|= BIT_N; n= 1; } else sreg&= ~BIT_N; if (D == 0x80) { sreg|= BIT_V; v= 1; } else sreg&= ~BIT_V; if ((n ^ v) & 1) sreg|= BIT_S; else sreg&= ~BIT_S; ram->set(SREG, sreg); return(resGO); } /* * Multiply * MUL Rd,Rr 0<=d<=31, 0<=r<=31 * 1001 11rd dddd rrrr *____________________________________________________________________________ */ int cl_avr::mul_Rd_Rr(t_mem code) { t_addr d, r; t_mem D, R, result, resl, resh; d= (code>>4) & 0x1f; r= ((code&0x200)>>5) | (code&0xf); D= ram->read(d); R= ram->read(r); result= R*D; resl= result & 0xff; resh= (result>>8) & 0xff; ram->write(0, resl); ram->write(1, resh); t_mem sreg= ram->read(SREG) & ~BIT_C; if (resh & 0x80) sreg|= BIT_C; ram->write(SREG, sreg); tick(1); return(resGO); } /* * Add Immediate to Word * ADIW Rdl,K dl={24,26,28,30}, 0<=K<=63 * 1001 0110 KK dd KKKK *____________________________________________________________________________ */ int cl_avr::adiw_Rdl_K(t_mem code) { t_addr dl; t_mem D, K, result, res; dl= 24+(2*((code&0x30)>>4)); K= ((code&0xc0)>>2)|(code&0xf); D= ram->read(dl+1)*256 + ram->read(dl); result= D+K; res= result & 0xffff; t_mem resl= result&0xff, resh= (result>>8)&0xff; ram->write(dl+1, resh); ram->write(dl, resl); t_mem sreg= ram->get(SREG); if (!res) sreg|= BIT_Z; else sreg&= ~BIT_Z; if (D&res&0x8000) sreg|= (BIT_V|BIT_S); else sreg&= ~(BIT_V|BIT_S); if (res & 0x8000) { sreg|= BIT_N; sreg^= BIT_S; } else sreg&= ~BIT_N; if ((~res)&D&0x8000) sreg|= BIT_C; else sreg&= ~BIT_C; ram->set(SREG, sreg); tick(1); return(resGO); } /* * Substract Immediate from Word * SBIW Rdl,K dl={24,26,28,30}, 0<=K<=63 * 1001 0111 KK dd KKKK *____________________________________________________________________________ */ int cl_avr::sbiw_Rdl_K(t_mem code) { t_addr dl; t_mem D, K, result, res; dl= 24+(2*((code&0x30)>>4)); K= ((code&0xc0)>>2)|(code&0xf); D= ram->read(dl+1)*256 + ram->read(dl); if (K & 0x20) K|= ~0x3f; if (D & 0x8000) D|= ~0xffff; result= (signed)D-(signed)K; res= result & 0xffff; t_mem resl= res&0xff, resh= (res>>8)&0xff; ram->write(dl+1, resh); ram->write(dl, resl); t_mem sreg= ram->get(SREG) & ~(BIT_S|BIT_V|BIT_N|BIT_Z|BIT_C); int n= 0, v= 0; if (0x8000 & D & (~res)) { sreg|= BIT_V; v= 1; } if (res & 0x8000) { sreg|= BIT_N; n= 1; } if ((n ^ v) & 1) sreg|= BIT_S; if (!res) sreg|= BIT_Z; if (0x8000 & res & (~D)) sreg|= BIT_C; ram->set(SREG, sreg); tick(1); return(resGO); } /* End of avr.src/arith_inst.cc */