copyleft: gplv3 added and set repo to public
[calu.git] / 3c_disasm / instr / branch.cpp
1 /*   `Deep Thought', a softcore CPU implemented on a FPGA
2
3     Copyright (C) 2010 Markus Hofstaetter <markus.manrow@gmx.at>
4     Copyright (C) 2010 Martin Perner <e0725782@student.tuwien.ac.at>
5     Copyright (C) 2010 Stefan Rebernig <stefan.rebernig@gmail.com>
6     Copyright (C) 2010 Manfred Schwarz <e0725898@student.tuwien.ac.at>
7     Copyright (C) 2010 Bernhard Urban <lewurm@gmail.com>
8
9     This program is free software: you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation, either version 3 of the License, or
12     (at your option) any later version.
13
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18
19     You should have received a copy of the GNU General Public License
20     along with this program.  If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "../Iinstr.hpp"
23
24 class Cbranch : public Iinstr {
25         private:
26                 bool m_taken;
27                 char m_typ;
28         public:
29                 Cbranch();
30                 void evalInstr();
31                 void execInstr();
32                 std::string toString();
33                 Iinstr* getNew();
34 };
35
36 /**
37  * Name:      create_instruction
38  * Purpose:   if compiled as shared library, this functions creates the 
39               instruction object
40
41  * Returns:   pointer to instruction object
42  */
43 extern "C" Iinstr* create_instruction() {
44     return new Cbranch();
45 }
46
47 Iinstr* Cbranch::getNew()
48 {
49         return new Cbranch();
50 }
51 /**
52  * Name:      destroy_instruction
53  * Purpose:   if compiled as shared library, this functions destoys the 
54               instruction object
55
56  * Parameter: IInstruction - the instruction object to delete
57  */
58 extern "C" void destroy_instruction(Iinstr* p) {
59     delete p;
60 }
61
62 Cbranch::Cbranch() : m_taken(1), m_typ(0)
63 {
64         opcode = B5(10110);
65         name = "branch";
66 }
67
68 void Cbranch::evalInstr()
69 {
70         this->m_s = argbits[0];
71         this->m_taken = argbits[1];
72
73         argbits >>= 2;
74
75         dynamic_bitset<> type = argbits;
76         type.resize(2);
77         this->m_typ = type.to_ulong();
78
79         switch(this->m_typ) {
80                 case 0:
81                         this->name = "br";
82                         break;
83                 case 1:
84                         this->name = "call";
85                         break;
86                 case 2:
87                         this->name = "ret";
88                         this->clockcount = 3;
89                         break;
90                 case 3:
91                         this->name = "reti";
92                         this->clockcount = 3;
93                         break;
94                 default:
95                         cerr << "What have you done? 2 bits that have more than 4 values?!" << endl;
96         }
97
98         argbits >>= 5;
99
100         dynamic_bitset<> immb = argbits;
101         immb.resize(16);
102         this->m_imm = this->generate16ImmSign(immb.to_ulong())*4;
103
104 }
105
106 void Cbranch::execInstr()
107 {
108         //cout << "should exec " << this->toString() << endl;
109         CDat pc = this->m_cpu->getCurPC();
110         switch(this->m_typ) {
111                 case 1:
112                         {
113                         CDat sp = this->m_cpu->getStack();
114                         sp -= 4;
115                         this->m_cpu->setRAM(sp, this->m_cpu->getNextPC());
116                         this->m_cpu->setStack(sp);
117                         }
118                         /* fall through */
119                 case 0:
120                         this->m_cpu->setNextPC(pc+(this->m_imm));
121                         break;
122                 case 2:
123                 case 3:
124                         this->m_cpu->setNextPC(this->m_cpu->getRAM(this->m_cpu->getStack()));
125                         this->m_cpu->setStack(this->m_cpu->getStack()+4);
126                         break;
127                 default:
128                         // nothing
129                         this->m_cpu->setNextPC(400);
130         }
131 }
132
133 std::string Cbranch::toString()
134 {
135         stringstream op;
136         op << this->getName();
137
138         if(m_s) op << 'S';
139
140         op << this->getConditionFlag() << (m_taken ? '+' : '-');
141         if(m_typ < 2) {
142                 op << " 0x" << std::hex << m_imm << "(" << std::dec << m_imm << ", " << (int) m_imm << ")";
143         }
144         return op.str();
145 }