├── CMakeLists.txt
├── LICENSE
├── README.md
├── img
├── photo_2022-01-15_04-35-41.jpg
└── photo_2022-01-15_04-35-47.jpg
├── inc
├── asm_disasm.h
└── kyiv.h
├── libs
├── komytators.txt
├── runge_kutta.txt
└── sqrt_and_friends
├── mem
├── ROM.txt
├── magnetic_drum.txt
├── punc_cards_out.txt
└── punched_tape.txt
└── src
├── asm_disasm.cpp
└── main.cpp
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16)
2 | project(kyivemu)
3 |
4 | set(CMAKE_CXX_STANDARD 17)
5 |
6 | find_package(Boost 1.71.0 COMPONENTS program_options REQUIRED)
7 | include_directories(${Boost_INCLUDE_DIR})
8 |
9 | include_directories(inc)
10 |
11 | add_executable(kyivemu src/main.cpp src/asm_disasm.cpp inc/kyiv.h inc/asm_disasm.h)
12 |
13 | target_link_libraries(kyivemu Boost::program_options)
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Olha Liuba
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kyiv_emulator
2 |
3 | ## Description
4 | This project aims to create an emulator of one of the oldest computers in Europe - "ЕОМ Київ"(Kyiv).
5 | "Kyiv" was developed in 1957. The developers team included Kateryna Yushchenko, Viktor Glushkov, Boris Gnatenko, Kateryna Shkabara and others.
6 | Though, in terms of memory and reliability "Kyiv" wasn't the best for its times, but its architecture, in terms of ease of writing programs, was advanced and actually paved the way for new types of computers that are much more powerful than its peers, as computers of that time were intended exclusively for calculations and programming in machine code and low-level languages.
7 |
8 | "Kyiv" is the world's first computer, which from the very beginning laid down the needs of programmers, in particular: the ability to easily implement compilers, text processing, asynchronous control, image processing, the ability to solve logical problems and implement information systems.
9 |
10 | Kateryna Yushchenko, one of the "Kyiv"'s inventors, according to pr. Yuiriy Yushchenko, implemented poiners in the machine before it is officially considered to. Also, according to A.P. Oleh Fareniuk, "Kyiv" was the first machine that implemented RISC ISA.
11 |
12 | ## Installation
13 | In future we want to host emulator as web application, till then you can compile source code or install application
14 | ```{bash}
15 | $ git clone https://github.com/oliuba/Kyiv_emulator.git
16 | $ cd Kyiv_emulator
17 | $ mkdir build
18 | $ cd build
19 | $ cmake ..
20 | $ make
21 | $ ./kyivemu
22 | ```
23 |
24 | ## Coding system and registers
25 |
26 | The Kyiv computer has 41-bit cells:
27 | 
28 | The 41-st bit is a sign bit (0 if number is positive and 1 when is negative), which means that there are negative 0 which is actually used in some of the programs.
29 | The numbers are fixed point - the point is situated before 40s bit, which means that there are only number from range (0, 1).
30 | 
31 | Commands are encoded as shown on picture 2. There are 5 bits of opcode and then 3\*12 bits of addresses. The 12th bit as modification bit, which indicates if the following address should be modificated by adding to it value of register A. For convinience the addresses are written the next way: k'i + e'i\*A', where k'i is address without modification bit, e'i - modification bit and A - value of register A.
32 |
33 |
34 | ##### Registers
35 |
36 | A register - modification register
37 | P register - return register
38 | Ц register - loop register
39 | C register - command counter (contains command that is currently executed)
40 | K register - command register
41 | T trigger-register - stop register
42 |
43 |
44 | ## Memory
45 |
46 | 1. RAM - addresses from 0000 to 1777 (the 0000 address always has 0);
47 | 1. ROM - addresses from 3000 to 3777 where:
48 | 1. 8 first cells are inputed codes, addresses 3000-3007.
49 | 1. 184 cells - permanently soldered codes, addresses 3010-3277. It containes some constants that are frequently used in programmes and some of the basic programmes.
50 | 1. 320 cells - interchangeable-soldered codes, addresses 3300-3777. It is blocks with 64 codes each that contain library programs.
51 |
52 | ## Standart programs permanently soldered memory.
53 |
54 | They usually take their argumet from address 0002 and return their result to address 0003.
55 |
56 | 1. Conversion from binary system to decimal (-1 < x < 1), starting address - 3100.
57 | 1. 1/2*sin(x) (-1 < x < 1), starting address - 3152.
58 | 1. 1/2*cos(x) (-1 < x < 1), starting address - 3174.
59 | 1. 1/2*sin(x) (-2*pi < x < 2*pi), starting address - 3264.
60 | 1. 1/2*cos(x) (-2*pi < x < 2*pi), starting address - 3217.
61 | 1. 1/n*ln(x) (0 < x < 1), starting address - 3166. This programm returns 2 values: 0003 - for ln and 0004 for value M.
62 | 1. sqrt(x) (2^(-22) < x < 1), starting address - 3163.
63 | 1. 1/4*e^x (-1 < x < 1), starting address - 3202.
64 | 1. 1/pi*arcsin(x) (-1 < x < 1), starting address - 3242.
65 | 1. 1/pi*arccos(x) (-1 < x < 1), starting address - 3244.
66 |
67 | While debugging the 8th program, we found value of an unknown cell 3201 which contains 1/32.
68 |
69 | There are also implemented some programs from interchangeable-soldered memory:
70 |
71 | Block #1:
72 |
73 |
74 | 1. sqrt(x) with range (0 <= x < 1). (Return result * 0.25) adresses 3300-3317.
75 | 1. scalar product of 2 vectors, addresses 3200-3333, starting address - 3320.
76 | 1. Multiplication of square matix on a vector, addresses 3334-3357, starting address - 3334.
77 | 1. 1/4*a^x, address 3360-3374, starting address 3360.
78 |
79 | Block #4:
80 |
81 | Calculation of system of differential equations by Runge-Kutta method, starting address 3600.
82 |
83 | Also interchangeable-soldered memory has much more programs, for example software implementation of floating point numbers.
84 |
85 | ## Assembler/disassembler
86 |
87 | In Kyiv emulator there are implemented assembler and disassembler. Assembler converts programs to octal code and looks like this:
88 |
89 | ```
90 | .text
91 | org 3163
92 | add 0000 3035 0003
93 | jump1:
94 | div 0002 0003 0004
95 | sub 0004 0003 0004
96 | rmul 0004 3042 0004
97 | add 0003 0004 0003
98 | jlea 3047 0004 jump1
99 | ret 0000 0000 0000
100 | .data
101 | org 0002
102 | 0.04
103 | ```
104 |
105 | where '.text' - code of the program, org [address] - starting address of the program or place to put data, '.data' - values, 'jump[number]' - label of the jump.
106 | Disassembler converts octal programs to assembly, identifies jumps and addresses of modification.
107 | There is also implemented disassembler for debugging that translates commands while the programm is running and outputs values of the cells.
108 |
109 | ## Kyiv Programs
110 | Kyiv has 29 operations:
111 |
112 | Just for k1,2,3 :
113 |
114 | k1 = '(A1+E1A)
115 |
116 | 'k1 = A1
117 |
118 | | Opcode | instruction (en) | description | | STOP |
119 | |:---------------------------: |:----------------: |:----------------------------------------: |----------------------------------------------------------------------------------------------------------------------- |-------------- |
120 | | Arithmetic operations | | | | |
121 | | 01 | add | addition | k1+k2=>k3 'C+1=>C | \|res\| ≥ 1 |
122 | | 02 | sub | substruction | k1-k2=>k3 'C+1=>C | \|res\| ≥ 1 |
123 | | 03 | adc | addition of commands | \| k1 + \|k2\| \| V sign of k2 => k3 'C+1=>C | |
124 | | 06 | suba | modulus substraction | \|k1\| - \|k2\| => k3 'C+1=>C | |
125 | | 07 | addcyc | cyclical addition | k1+k2=>k3 if res ≥ 1 : k3 & k1 >> 40 ( carry from the sign bit goes to the least significant bit of the res ) 'C+1=>1 | |
126 | | 10 | mul | multiplication without rounding | k1*k2=>k3 res>>40 'C+1=>C | |
127 | | 11 | rmul | multiplication with rounding | k1*k2=>k3 res += 1<<39 res>>40 (1 is added to the highest of the discarded bits.) 'C+1=>C | |
128 | | 12 | div | division | k1/k2=>k3 'C+1=>C | |
129 | | Logical operations | | | | |
130 | | 13 | sh | logical shift | if k2 < 0 >> else << k1 >>/<< n => k3 n -- the number of orders of 3rd address of k2 'C+1=>C | |
131 | | 14 | and | digital logical addition | k1 & k2 => k3 'C+1=>C | |
132 | | 15 | or | digital logical "multiplication" | k1 \| k2 => k3 'C+1=>C | |
133 | | 17 | xor | digital logical operation nonequivalence | k1 XOR k2 => k3 'C+1=>C | |
134 | | 35 | norm | normalization | k1 -- normalized exponent => k2 mantissa => k3 'C+1=>C | |
135 | | Control transfer operations | | | | |
136 | | 04 | jle | if 1 ≤ 2 | if k1 ≤ k2: k3=>C else: 'C+1=>C | |
137 | | 05 | jlea | if \| 1 \| ≤ \| 2 \| | if \|k2\| ≤ \|k2\|: k3=>C else: 'C+1=>C | |
138 | | 16 | je | if 1 = 2 | if k1 == k2: k3=>C else: 'C+1=>C | |
139 | | 30 | nfork | if 1 ≤ -0 | if k1 ≤ -0: k3=>C k2=>P else: 'C+1=>C | |
140 | | 31 | ncall | 1 ≤ -0 | if k1 ≤ -0: k3=>C else k2=>C | |
141 | | 32 | ret | return | | |
142 | | Modification of addresses | | | | |
143 | | 26 | gob | beginning of a group operation | k1=>Ц(loop) k2=>A if A=Ц: k3=>C else: 'C+1=>C | |
144 | | 27 | goe | end of a group operation | A+k1=>A if A=Ц: k3=>C else: k2=>C | |
145 | | 34 | fop | call on the retainer (F) | second address of k1 ==> A 'A=>k3 'C+1=>C | |
146 | | Input/Output | | | | |
147 | | 20 | rdt | input of data from punched card | read data to 'k1, 'k1+1,..,'k2. Start reading with offset k3 | |
148 | | 21 | rbn | input of command from punched card | read command to 'k1, 'k1+1,...,'k2. Start reading with offset k3 | |
149 | | 22 | wbn | output to punched card | write 'k1, 'k1+1,...'k2 to card | |
150 | | 23 | wmd | write to magnetic drum | write 'k1, 'k1+1,...'k2 to drum | |
151 | | 24 | rmd | read from magnetic drum | read from drum and write to 'k1, 'k1+1,..., 'k2 | |
152 | | 25 | imd | init magnetic dram | k2 -- number of magnetic dram (3 max) number of road k3 -- offset k1 -- 0 if read, 1 -- of write 'C+1=>C | |
153 | | 33 | ostanov | stop | | |
154 | ## GUI Usage
155 |
156 | GUI consists of such main parts:
157 |
158 | 1. Signalization panel
159 |
160 | It demonstrates the inner work of "Kyiv" at the time of command execution.
161 | 1. The first row shows binary result of the command execution - data that is written to the third address of the command.
162 | 2. The second row shows the content of the number register - the number that is transported from or to a magnetic drum. Works with the commands 023 (write magnetic deum) or 024 (read magnetic drum).
163 | 3. The left part of third and forth rows (KOп) is a set of bulbs that are responsible for the executed opcode. When a command is executed, one of 29 bulbs lights up.
164 | 4. The bulb "Тр Выб" ligths up if there is an exchange with punch tape, punch card or magnetic drum.
165 | 5. The middle part of the third row is the indicator of the address register - it works in the takt mode and shows the address of a certain takt's address.
166 | 6. The middle part of the forth row shows the content of the return register.
167 | 7. The bulp "Тр Пр" light up if there is the command of jumps if the jump is made.
168 | 8. The last part of the third row is meant for takt control of "Kyiv": it demonstrates the start and end of most important parts of command execution.
169 | 9. The last part of the forth row shows the content of the command counter register.
170 | 10. The fifth row shows the content of the command register in the binary-octal mode, usual for "Kyiv" where first 5 bulbs stand for opcode, then each 12 represent first, second and third addresses respectively.
171 | 11. The sixth row shows the content of intrmediate register to which the content of number register is written.
172 | 12. The seventh row contains three parts. Unfortunately, we don't know the purpose of the most left one. The middle one contains the address register's contant, and the rigth part - the contant of the loop register. There are also three buttons: "Нач" and "Гот" for beginning and start of a command execution, and "Авт" for the work of the machine in an automatic mode.
173 |
174 | 
175 |
176 | 2. Control panel
177 |
178 | It emulates the work of the control panel, from which it is possible to change the settings of the machine, change ROM and execute an own command.
179 |
180 | There is an upper and lower part of the panel:
181 |
182 | 1. The upper part contains some of the set codes - three cells 03000-03002 of ROM which may be chosen by setting the first button on and choosing the values for each digit (in binary-octal) of three buttons.
183 | 2. The lower part contains some triggers, tumblers, addresses and command:
184 | - the first row contains buttons for a command. If the first button is checked, it is possible to execute the chosen command (in binary-octal).
185 | - the trigger of emergency stop is checked when the machine works in the usual state, where if there is a stop in "Kyiv", T register is enabled and one command is skipped. Otherwise T register remains the same, and the two commands are skipped.
186 | - The next trigger is disabled when there is a need to block command counter register (for example, to execute the same command many times for debugging).
187 | - The trigger "Пч" is used for print but is currently not implemented.
188 | - The next trigger blocks registers of address, loop and return.
189 | - The trigger "Переск - ОСТ" blocks stop, so that there never occurs stop of machine when this trigger is enabled, even when it should occur in normal mode.
190 | - Tumbler "Авт-Цикл-Такт" is set to "Авт" when machine works in its usual automatic mode, "Цикл" - when each command is executed one by one, and "Такт" when each command is executed by 4 tats one by one. Each new step occurs when the key "K" is pressed.
191 | - Tumbler "Норм раб - Ввод - Уст с ПУ" is set to "Норм раб" when the machin works in a normal mode, "Ввод" - when the user wants to change the content of the set codes in the upper panel or the command in the lower panel, and "Уст с ПУ" to load these changes into machine (execute the command or save set codes to ROM).
192 | - The next trigger sets all registers to zero.
193 | - Button "Останов" stops the machine if the stop block is disabled.
194 | - Tumbler "Нейтральное - По N команды - По III адресу" is set to "Нейтральное" when the normal stop works (during program execution), "По N команды" - machine stops when it executes the same command as on the lower panel, and "По III адресу" - machine stops when the executed command's third address is the same as in the nearby cells.
195 |
196 | 
197 |
198 | 3. Set codes of ROM (cells 03000 - 03007)
199 |
200 | It contains the set codes - eight cells 03000-03007 of ROM. By default contains zeros. If one of the cells is chosen on the control panel, machine works with it, otherwise - with the cell from here.
201 |
202 | 
203 |
204 | 4. Assembly input / opening from file
205 |
206 | It contains two parts:
207 |
208 | 1. The place for assember code. It may be entered directly in the field or chosen from text file using the below button.
209 | 2. The place for assembled code. It is impossible to write there, it only shows the "Kyiv" direct commands from the assembler code after clicking on button "Assembly".
210 |
211 | 
212 |
213 | 5. Three magnetic drums
214 |
215 | 
216 |
217 | 6. Punch cards
218 |
219 | ## Authors
220 | * [Anna Korabliova](https://github.com/anika02)
221 | * [Diana Hromiak](https://github.com/Diana-Doe)
222 | * [Daria Minieieva](https://github.com/DariaMinieieva)
223 | * [Olha Liuba](https://github.com/oliuba)
224 | * [Hanna Yershova](https://github.com/hannusia)
225 |
--------------------------------------------------------------------------------
/img/photo_2022-01-15_04-35-41.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ucu-computer-science/Kyiv_emulator/7c82f9eb22d0eee95e3de6f90f7bc89ce5995234/img/photo_2022-01-15_04-35-41.jpg
--------------------------------------------------------------------------------
/img/photo_2022-01-15_04-35-47.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ucu-computer-science/Kyiv_emulator/7c82f9eb22d0eee95e3de6f90f7bc89ce5995234/img/photo_2022-01-15_04-35-47.jpg
--------------------------------------------------------------------------------
/inc/asm_disasm.h:
--------------------------------------------------------------------------------
1 | #ifndef KYIVEMU_ASM_DISASM_H
2 | #define KYIVEMU_ASM_DISASM_H
3 |
4 | int disassembly(const uint64_t & command_oct, Kyiv_memory_t & kmem, const addr3_t &addr3);
5 | int check_modification(std::string addr);
6 | int disassembly_text(const std::string file_from, const std::string file_to);
7 | std::string mod_comment(std::string addr_1, std::string addr_2, std::string addr_3);
8 | int disassembler_second_pass(std::map program, std::map jumps, const std::string& file_to);
9 | int write_file(const char* filename, std::string &res);
10 | #endif //KYIVEMU_ASM_DISASM_H
--------------------------------------------------------------------------------
/inc/kyiv.h:
--------------------------------------------------------------------------------
1 | #ifndef KYIVEMU_KYIV_H
2 | #define KYIVEMU_KYIV_H
3 |
4 | #include
5 |
6 | typedef uint64_t addr_t;
7 | typedef uint64_t word_t;
8 | typedef int64_t signed_word_t;
9 | typedef uint32_t opcode_t;
10 | typedef boost::multiprecision::int128_t mul_word_t;
11 |
12 | struct addr3_t{
13 | addr_t source_1 = 0, source_2 = 0, destination = 0;
14 | constexpr addr3_t() = default;
15 | };
16 |
17 | constexpr addr3_t word_to_addr3(word_t w);
18 | constexpr opcode_t word_to_opcode(word_t w);
19 | constexpr bool is_negative(word_t w);
20 | constexpr word_t to_negative(word_t w);
21 | constexpr word_t to_positive(word_t w);
22 | constexpr uint16_t leftmost_one(word_t w);
23 | uint16_t leftmost_one(mul_word_t w);
24 | signed_word_t get_absolute(word_t w);
25 | signed_word_t word_to_number(word_t w);
26 | constexpr bool get_A1(word_t w);
27 | constexpr bool get_A2(word_t w);
28 | constexpr bool get_A3(word_t w);
29 | constexpr addr3_t shift_addr3_byA(addr3_t addr3, uint64_t offset, word_t w);
30 |
31 |
32 | struct aproxy {
33 | aproxy(word_t& r, addr_t addres) : mPtr(&r), ref(addres) {}
34 | void operator = (word_t n) const {
35 | if (ref > 03000) {
36 | throw "ROM!";
37 | }
38 | *mPtr = n;
39 | }
40 | operator word_t() {
41 | return *mPtr;
42 | }
43 | void operator |=(word_t x) const {
44 | *mPtr = *mPtr | x;
45 | }
46 | void operator &=(word_t x) const {
47 | *mPtr = *mPtr & x;
48 | }
49 | addr_t ref;
50 | word_t *mPtr;
51 | };
52 |
53 | class memory_error: public std::runtime_error{
54 | addr_t err_addr;
55 | public:
56 | memory_error(const std::string& err_descr_, addr_t addr_ ): std::runtime_error{err_descr_}, err_addr(addr_)
57 | {}
58 | };
59 |
60 | class out_of_range_error: public memory_error {
61 | public:
62 | out_of_range_error(const std::string& err_descr_, addr_t addr_ ): memory_error{err_descr_, addr_}
63 | {}
64 | };
65 |
66 | class ROW_write_error: public memory_error {
67 | public:
68 | ROW_write_error(const std::string& err_descr_, addr_t addr_ ): memory_error{err_descr_, addr_}
69 | {}
70 | };
71 |
72 |
73 | class Kyiv_memory_t {
74 | private:
75 | word_t mem_array_m[04000] = {0}; // 0AAAA -- octal constant};
76 |
77 |
78 | //! Оператор може змінювати деякі значення ROM
79 | void internal_set_ROM_values(addr_t addr, word_t val){
80 | // Перевірки додати, чи що? З пульта не всі змінюються. Або хай тим реалізація пульта займається?
81 | // if (addr >= max_RAM_addr){
82 | // throw out_of_range_error("Writing to ROM", addr);
83 | // }
84 | mem_array_m[addr] = val;
85 | }
86 |
87 | public:
88 | static constexpr addr_t min_addr = 0;
89 | static constexpr addr_t min_RAM_addr = 0;
90 | static constexpr addr_t min_ROM_addr = 03000;
91 | static constexpr addr_t max_RAM_addr = min_ROM_addr; //! Напіввідкритий інтервал, як із вказівниками:
92 | //! Коректні адреси: [min_RAM_addr, max_RAM_addr)
93 | static constexpr addr_t max_ROM_addr = 04000;
94 | static constexpr addr_t max_addr = 04000;
95 |
96 | constexpr word_t read_memory(addr_t addr) const {
97 | if(addr >= max_ROM_addr){
98 | throw out_of_range_error("Wrong address while reading", addr);
99 | }
100 | return mem_array_m[addr];
101 | }
102 | void write_memory(addr_t addr, word_t val){
103 | if(addr >= max_ROM_addr){
104 | throw out_of_range_error("Wrong address while writing", addr);
105 | } else if (addr >= max_RAM_addr){
106 | throw out_of_range_error("Writing to ROM", addr);
107 | }
108 | mem_array_m[addr] = val;
109 | }
110 |
111 | void write_rom(addr_t addr, word_t val) {
112 | if(addr >= max_ROM_addr){
113 | throw out_of_range_error("Wrong address while writing", addr);
114 | } else if (addr < min_ROM_addr){
115 | throw out_of_range_error("Writing to RAM", addr);
116 | }
117 | mem_array_m[addr] = val;
118 | }
119 |
120 | };
121 |
122 |
123 | class Kyiv_memory {
124 | private:
125 | word_t k[04000] = {0, 0'12'0004'0005'0007ULL, 0'02'0004'0005'0007ULL,
126 | 100, 4, 5, 6, 7, 8, 1099511627775, 549755813888, 16, 219902328832, 16, 549755813888
127 | };
128 | public:
129 | auto operator[](addr_t addres) {
130 | return aproxy(k[addres], addres);
131 | }
132 |
133 | };
134 |
135 |
136 | // Контроль виходу за розмір додати потім. Це дуже груба реалізація.
137 | struct Kyiv_t{
138 | // bitfield-и тут мають один нюанс, тому не юзаю
139 | //! Увага, ми біти нумеруємо з нуля, вони - з 1, тому 40 = 41-1 і т.д.
140 |
141 | //! TODO: Які вони там значення при включенні мали? Як це керувалося?
142 | uint64_t C_reg = 0, K_reg = 0, P_reg = 0, Loop_reg = 0, A_reg = 0, B_tumb = 0;
143 | // B_tumb is not bool because according to p. 163 Glushkov-Iushchenko it has 3 modes.
144 | // Maybe there is a better way to handle this?
145 | bool T_reg = false;
146 | size_t h = 0;
147 |
148 | int perfo_num = 0;
149 | int drum_num_read = 0;
150 | int drum_zone_read = 0;
151 | int drum_num_write = 0;
152 | int drum_zone_write = 0;
153 |
154 |
155 | //! ! TODO: Пам'ять певне потрібно виділити в нову сутність -- клас, який зразу відповідатиме і за
156 | //! захист пам'яті, поведінку при переповненні і т.д. -- я поки тим не заморочувався.
157 | //! Нульова адреса має завжди містити 0.
158 | //! Найпростіше, певне, буде створити свій клас, який перевизначає оператор [], і все це реалізовує.
159 | //! Тоді решта коду не потребуватиме зміни.
160 | Kyiv_memory_t kmem;
161 |
162 | //! TODO: Придумати адекватні мнемоніки
163 | enum arythm_operations_t{
164 | opcode_add = 0'01,
165 | opcode_sub = 0'02,
166 | opcode_addcmd = 0'03,
167 | opcode_subabs = 0'06,
168 | opcode_addcyc = 0'07,
169 | //! Ймовірно, ці три операції враховують fixed-point природу чисел "Києва"
170 | opcode_mul = 0'10, //! УВАГА -- це нетривіальна операція!
171 | opcode_mul_round = 0'11, //! УВАГА -- це нетривіальна операція!
172 | opcode_div = 0'12, //! УВАГА -- це нетривіальна операція!
173 | opcode_norm = 0'35, // Іноді відносять до логічних операцій
174 | };
175 | // Логічні операції працюють над всіма 41 бітами
176 | enum logic_operations_t{
177 | opcode_log_shift = 0'13,
178 | opcode_log_or = 0'14, // Логічне додавання в тексті
179 | opcode_log_and = 0'15, // Логічне множення в тексті
180 | opcode_log_xor = 0'17, // Нерівнозначність в тексті
181 | };
182 | enum flow_control_operations_t{
183 | opcode_jmp_less_or_equal = 0'04,
184 | opcode_jmp_abs_less_or_equal = 0'05,
185 | opcode_jmp_equal = 0'16,
186 | opcode_fork_negative = 0'31, // <=-0, дві гілки
187 | opcode_call_negative = 0'30, // <=-0 -- не забудьте, що +0 -- немає стрибка
188 | opcode_ret = 0'32,
189 | // Операції над адресами
190 | opcode_group_op_begin = 0'26,
191 | opcode_group_op_end = 0'27,
192 | opcode_F = 0'34,
193 | opcode_stop = 0'33, // TODO: Він ніби в десятковому у таблиці -- перевірити
194 | };
195 |
196 | enum IO_operations_t{
197 | opcode_read_perfo_data = 0'20,
198 | opcode_read_perfo_binary = 0'21,
199 | opcode_write_perfo_binary = 0'22,
200 | opcode_init_magnetic_drum = 0'25,
201 | opcode_read_magnetic_drum = 0'24, // В Глушко-Ющенко помилка в табл. на стор 180.
202 | opcode_write_magnetic_drum = 0'23,
203 | };
204 |
205 | Kyiv_t() {
206 | std::string rom_file = "../ROM.txt";
207 | std::ifstream infile(rom_file);
208 | std::string line;
209 | while (std::getline(infile, line)) {
210 | line.erase(remove_if(line.begin(), line.end(), isspace), line.end());
211 | std::ostringstream str;
212 | str << std::oct << line;
213 | std::string data = str.str();
214 | std::string address = data.substr(0, 4);
215 | data = data.substr(4);
216 | if (data.size() != 13 && data.size() != 14) {
217 | continue;
218 | }
219 | if (data.size() != 14) {
220 | data.insert(0, "0");
221 | }
222 | kmem.write_rom(std::stoi(address, 0, 8), std::stol(data, 0, 8));
223 | }
224 | }
225 |
226 | bool execute_opcode();
227 |
228 | void opcode_flow_control(const addr3_t& addr3_shifted, opcode_t opcode, const addr3_t &addr3);
229 |
230 | void opcode_arythm(const addr3_t &addr3, opcode_t opcode);
231 | };
232 |
233 |
234 | #endif //KYIVEMU_KYIV_H
235 |
--------------------------------------------------------------------------------
/libs/komytators.txt:
--------------------------------------------------------------------------------
1 | 3300 01 0000 3621 0026
2 | 3301 01 0000 3622 0027
3 | 3302 02 3000 3011 0014
4 | 3303 14 3050 3026 0012
5 | 3304 01 0014 3011 0014
6 | 3305 34 0014 0000 0011
7 | 3306 15 0011 3025 0013
8 | 3307 16 0013 3600 3430
9 | 3310 16 0013 3045 3333
10 | 3311 16 0013 3044 3333
11 | 3312 16 0013 3050 3461
12 | 3313 16 0013 3601 3333
13 | 3314 16 0013 3602 3323
14 | 3315 16 0013 3603 3317
15 | 3316 31 0000 3557 0000
16 | 3317 01 0011 0000 0010
17 | 3320 01 0014 3011 0014
18 | 3321 34 0014 0000 0011
19 | 3322 31 0000 0010 0000
20 | 3323 13 3604 0011 0014
21 | 3324 34 0014 0000 0014
22 | 3325 31 0014 3326 3330
23 | 3326 15 0011 3023 0014
24 | 3327 31 0000 3305 0000
25 | 3330 13 3624 0011 0011
26 | 3331 15 0011 3023 0014
27 | 3332 31 0000 3305 0000
28 | 3333 14 0013 3613 0025
29 | 3334 13 3624 0011 0017
30 | 3335 13 3604 0011 0016
31 | 3336 34 0011 0000 0015
32 | 3337 34 0016 0000 0020
33 | 3340 15 0020 3605 0021
34 | 3341 15 0020 3606 0022
35 | 3342 15 0015 3605 0023
36 | 3343 15 0015 3606 0024
37 | 3344 02 0022 0024 0016
38 | 3345 31 0016 3346 3410
39 | 3346 05 0016 3607 3352
40 | 3347 34 0017 0000 0000
41 | 3350 14 0000 0020 4000
42 | 3351 31 0000 3304 0000
43 | 3352 02 0000 0016 0016
44 | 3353 31 0023 3354 3356
45 | 3354 13 0016 0023 0023
46 | 3355 31 0000 0025 0000
47 | 3356 15 0023 3035 0023
48 | 3357 13 0016 0023 0023
49 | 3360 02 0000 0023 0023
50 | 3361 31 0000 0025 0000
51 | 3362 05 0022 3610 3365
52 | 3363 33 0000 0000 0000
53 | 3364 31 0000 3363 0000
54 | 3365 01 3012 0022 0022
55 | 3366 11 0021 3042 0021
56 | 3367 01 3042 0021 0021
57 | 3370 15 0021 3611 0016
58 | 3371 16 0000 0016 3375
59 | 3372 01 0021 3612 0021
60 | 3373 31 0000 3375 0000
61 | 3374 31 0000 3362 0000
62 | 3375 15 0021 3605 0021
63 | 3376 16 0021 0000 3446
64 | 3377 34 0017 0000 0000
65 | 3400 14 0021 0022 4000
66 | 3401 31 0000 3304 0000
67 | 3402 35 0021 0016 0021
68 | 3403 01 0016 0022 0022
69 | 3404 04 3012 0022 3370
70 | 3405 34 0017 0000 0000
71 | 3406 15 3026 0021 4000
72 | 3407 31 0000 3304 0000
73 | 3410 16 0000 0016 0025
74 | 3411 05 0016 3607 3415
75 | 3412 14 0000 0000 0021
76 | 3413 14 0024 0000 0022
77 | 3414 31 0000 0025 0000
78 | 3415 31 0021 3416 3421
79 | 3416 13 0016 0021 0021
80 | 3417 14 0024 0000 0022
81 | 3420 31 0000 0025 0000
82 | 3421 15 0021 3035 0021
83 | 3422 13 0016 0021 0021
84 | 3423 02 0000 0021 0021
85 | 3424 14 0024 0000 0022
86 | 3425 31 0000 0025 0000
87 | 3426 22 0000 0000 0000
88 | 3427 16 0000 0000 0000
89 | 3430 34 0011 0000 0015
90 | 3431 13 3624 0011 0017
91 | 3432 13 3604 0011 0016
92 | 3433 34 0016 0000 0020
93 | 3434 15 0020 3605 0021
94 | 3435 15 0020 3606 0022
95 | 3436 15 0015 3605 0023
96 | 3437 15 0015 3606 0024
97 | 3440 01 0022 0024 0022
98 | 3441 02 0022 3611 0022
99 | 3442 05 0022 3610 3445
100 | 3443 33 0000 0000 0000
101 | 3444 31 0000 3443 0000
102 | 3445 04 3012 0022 3451
103 | 3446 34 0017 0000 0000
104 | 3447 14 0000 0000 4000
105 | 3450 31 0000 3304 0000
106 | 3451 11 0021 0023 0021
107 | 3452 05 0021 0000 3456
108 | 3453 35 0021 0016 0021
109 | 3454 01 0016 0022 0022
110 | 3455 04 0000 0022 3376
111 | 3456 34 0017 0000 0000
112 | 3457 14 0000 0000 4000
113 | 3460 31 0000 3304 0000
114 | 3461 34 0011 0000 0015
115 | 3462 16 0015 0000 3363
116 | 3463 13 3624 0011 0017
117 | 3464 13 3604 0011 0016
118 | 3465 34 0016 0000 0020
119 | 3466 16 0020 0000 3477
120 | 3467 15 0020 3607 0021
121 | 3470 15 0020 3607 0022
122 | 3471 15 0015 3605 0023
123 | 3472 15 0015 3606 0024
124 | 3473 02 0022 0024 0022
125 | 3474 10 0022 3611 0022
126 | 3475 05 3610 0022 3363
127 | 3476 04 0000 0022 3502
128 | 3477 34 0017 0000 0000
129 | 3500 14 0000 0000 4000
130 | 3501 31 0000 3304 0000
131 | 3502 11 0021 3042 0021
132 | 3503 01 0022 3012 0022
133 | 3504 12 0021 0023 0021
134 | 3505 31 0000 3370 0000
135 | 3510 14 0000 0000 0007
136 | 3511 15 0004 3606 0005
137 | 3512 15 0004 3605 0006
138 | 3513 16 0005 0000 3551
139 | 3514 05 3625 0005 3524
140 | 3515 05 3623 0005 3532
141 | 3516 11 0006 3626 0006
142 | 3517 02 0007 3012 0007
143 | 3520 35 0006 0004 0006
144 | 3521 01 0004 0005 0005
145 | 3522 01 0005 3615 0005
146 | 3523 31 0000 3515 0000
147 | 3524 11 0006 3614 0006
148 | 3525 35 0006 0004 0006
149 | 3526 01 3012 0007 0007
150 | 3527 01 0004 0005 0005
151 | 3530 01 0005 3627 0005
152 | 3531 31 0000 3514 0000
153 | 3532 05 3611 0005 3536
154 | 3533 11 3042 0006 0006
155 | 3534 01 3012 0005 0005
156 | 3535 31 0000 3532 0000
157 | 3536 01 0000 0006 0002
158 | 3537 30 3026 3540 3100
159 | 3540 05 0007 3616 3547
160 | 3541 31 0007 3542 3544
161 | 3542 02 0007 3617 0004
162 | 3543 31 0000 3545 0000
163 | 3544 01 0007 3617 0004
164 | 3545 14 0004 3620 0004
165 | 3546 22 0003 0004 3304
166 | 3547 14 0007 0000 0004
167 | 3550 22 0003 0004 3304
168 | 3551 22 0006 0007 3304
169 | 3557 16 0013 0426 3510
170 | 3560 16 0013 0427 3564
171 | 3561 30 3026 3562 0011
172 | 3562 16 3026 0013 3630
173 | 3563 31 0000 3304 0000
174 | 3564 13 3624 0011 0017
175 | 3565 15 0011 3032 0021
176 | 3566 14 0021 3574 0021
177 | 3567 01 0021 0000 0011
178 | 3570 31 0000 3561 0000
179 | 3571 15 0017 3023 0014
180 | 3572 02 0014 3011 0014
181 | 3573 32 0000 0000 0000
182 | 3600 11 0000 0000 0000
183 | 3601 06 0000 0000 0000
184 | 3602 31 0000 0000 0000
185 | 3603 25 0000 0000 0000
186 | 3604 20 0000 0000 0014
187 | 3605 37 7777 7777 7600
188 | 3606 00 0000 0000 0177
189 | 3607 00 0000 0000 0041
190 | 3610 00 0000 0000 0176
191 | 3611 00 0000 0000 0100
192 | 3612 00 0000 0000 0200
193 | 3613 00 0021 0023 0021
194 | 3614 14 6314 6314 6320
195 | 3615 00 0000 0000 0004
196 | 3616 00 0000 0000 0011
197 | 3617 00 0000 0000 0012
198 | 3620 00 0000 0000 0020
199 | 3621 05 0000 0000 3402
200 | 3622 05 0000 0000 3362
201 | 3623 00 0000 0000 0075
202 | 3624 00 0000 0000 0014
203 | 3625 00 0000 0000 0101
204 | 3626 12 0000 0000 0000
205 | 3627 20 0000 0000 0003
206 | 3630 35 0000 0006 0000
207 | 3631 14 0000 0000 0017
208 | 3632 15 0011 3023 0005
209 | 3633 15 0011 3023 0005
210 | 3634 11 0004 3040 0003
211 | 3635 02 0005 0003 0007
212 | 3636 11 0003 3040 0005
213 | 3637 14 0004 0005 0005
214 | 3640 14 3630 0005 0004
215 | 3641 14 3050 3026 0005
216 | 3642 30 3026 3643 0004
217 | 3643 34 0003 0000 0000
218 | 3644 16 0000 4000 3650
219 | 3645 15 4000 3605 4000
220 | 3646 01 0006 3611 0006
221 | 3647 14 0006 4000 4000
222 | 3650 05 0007 0017 3655
223 | 3651 01 3011 0017 0017
224 | 3652 03 3016 0004 0004
225 | 3653 01 3011 0003 0003
226 | 3654 31 0000 3642 0000
227 | 3655 14 3011 0000 0017
228 | 3656 34 0011 0000 0000
229 | 3657 16 4000 0000 3304
230 | 3660 15 3605 4000 0004
231 | 3661 15 3606 4000 0005
232 | 3662 11 0011 3040 0006
233 | 3663 34 0006 0000 0000
234 | 3664 15 3605 4000 0022
235 | 3665 15 3606 4000 0010
236 | 3666 16 4000 0000 3702
237 | 3667 12 0022 0000 4000
238 | 3670 31 0000 3674 0000
239 | 3671 11 0022 3042 0022
240 | 3672 01 0010 3012 0010
241 | 3673 30 0000 3667 0000
242 | 3674 02 0010 0005 0010
243 | 3675 01 0010 3611 0010
244 | 3676 35 4000 0003 4000
245 | 3677 01 0003 0010 0010
246 | 3700 15 4000 3605 4000
247 | 3701 14 4000 0010 4000
248 | 3702 16 0017 0007 3304
249 | 3703 01 3011 0017 0017
250 | 3704 03 3011 0006 0006
251 | 3705 31 0000 3663 0000
--------------------------------------------------------------------------------
/libs/runge_kutta.txt:
--------------------------------------------------------------------------------
1 | 3600 01 0000 3043 0040
2 | 3601 11 0040 3075 0036
3 | 3602 11 3042 3075 0037
4 | 3603 34 3005 0000 0043
5 | 3604 01 3005 4000 0033
6 | 3605 01 0033 4000 0016
7 | 3606 01 0016 4000 0035
8 | 3607 01 0036 0000 0017
9 | 3610 01 0036 0000 0020
10 | 3611 01 3001 0000 0031
11 | 3612 01 3004 0000 0032
12 | 3613 01 0000 0000 0022
13 | 3614 01 0000 0000 0021
14 | 3615 04 3002 0031 3200
15 | 3616 01 0031 0000 0034
16 | 3617 01 3005 3011 0024
17 | 3620 01 0033 3011 0025
18 | 3621 01 0016 3011 0026
19 | 3622 34 0024 0000 0023
20 | 3623 34 0025 0000 0000
21 | 3624 01 0023 0000 4000
22 | 3625 34 0026 0000 0000
23 | 3626 01 0000 0023 4000
24 | 3627 01 0024 3011 0024
25 | 3630 01 0025 3011 0025
26 | 3631 01 0026 3011 0026
27 | 3632 04 0024 0033 3622
28 | 3633 05 0000 0000 3003
29 | 3634 01 0035 3011 0027
30 | 3635 01 3005 3011 0024
31 | 3636 02 0036 0020 0020
32 | 3637 01 0020 0017 0017
33 | 3640 04 0017 0037 3642
34 | 3641 02 0017 0037 0017
35 | 3642 34 0027 0000 0000
36 | 3643 11 4000 0017 0023
37 | 3644 34 0024 0000 0000
38 | 3645 01 4000 0023 4000
39 | 3646 01 0027 3011 0027
40 | 3647 01 0024 3011 0024
41 | 3650 04 0024 0033 3642
42 | 3651 16 0022 3042 3673
43 | 3652 02 0040 0021 0021
44 | 3653 01 0021 0022 0022
45 | 3654 11 3000 0022 0041
46 | 3655 01 0041 0034 0031
47 | 3656 01 0035 3020 0042
48 | 3657 02 0026 3011 0026
49 | 3660 02 0025 3011 0025
50 | 3661 02 0027 3011 0027
51 | 3662 34 0027 0000 0000
52 | 3663 11 0022 4000 0023
53 | 3664 34 0026 0000 0030
54 | 3665 34 0025 0000 0000
55 | 3666 01 0023 0030 4000
56 | 3667 04 0042 0027 3657
57 | 3670 01 0026 0043 0026
58 | 3671 01 0025 0043 0025
59 | 3672 04 0000 0000 3003
60 | 3673 02 0032 3011 0032
61 | 3674 01 3005 0000 0002
62 | 3675 30 0032 3612 3354
63 | 3676 05 0000 0000 3613
--------------------------------------------------------------------------------
/libs/sqrt_and_friends:
--------------------------------------------------------------------------------
1 | 3300 01 0000 0000 0003
2 | 3301 05 0002 0000 3317
3 | 3302 01 3035 0000 0003
4 | 3303 16 0002 3035 3317
5 | 3304 01 3043 0000 0005
6 | 3305 05 3043 0002 3311
7 | 3306 12 0002 3043 0002
8 | 3307 11 0005 3042 0005
9 | 3310 05 0000 0000 3305
10 | 3311 12 0002 0003 0004
11 | 3312 02 0004 0003 0004
12 | 3313 11 0004 3042 0004
13 | 3314 01 0003 0004 0003
14 | 3315 05 3021 0004 3311
15 | 3316 11 0003 0005 0003
16 | 3317 32 0000 0000 0000
17 | 3320 01 0000 0000 0003
18 | 3321 01 0002 3011 0005
19 | 3322 01 0004 3011 0006
20 | 3323 34 0002 0000 0007
21 | 3324 34 0006 0000 0010
22 | 3325 34 0005 0000 0000
23 | 3326 11 4000 0010 0011
24 | 3327 01 0003 0011 0003
25 | 3330 01 0005 3011 0005
26 | 3331 01 0006 3011 0006
27 | 3332 02 0007 3011 0007
28 | 3333 31 0007 3324 3146
29 | 3334 34 0002 0000 0006
30 | 3335 01 0002 4000 0007
31 | 3336 01 0006 0003 0005
32 | 3337 01 0002 3011 0010
33 | 3340 01 0003 3011 0012
34 | 3341 01 0004 3011 0011
35 | 3342 01 0000 0000 0015
36 | 3343 34 0010 0000 0013
37 | 3344 34 0011 0000 0000
38 | 3345 11 0013 4000 0014
39 | 3346 01 0014 0015 0015
40 | 3347 01 0010 3011 0010
41 | 3350 01 0011 3011 0011
42 | 3351 05 0010 0007 3343
43 | 3352 34 0012 0000 0000
44 | 3353 01 0015 0000 4000
45 | 3354 01 0012 3011 0012
46 | 3355 01 0007 0006 0007
47 | 3356 05 0012 0005 3341
48 | 3357 32 0000 0000 0000
49 | 3360 01 0000 3035 0011
50 | 3361 01 0000 0007 0002
51 | 3362 30 3026 3363 3116
52 | 3363 11 0003 0010 0012
53 | 3364 05 0012 0004 3370
54 | 3365 01 0012 0004 0012
55 | 3366 11 0011 3065 0011
56 | 3367 05 0000 0000 3364
57 | 3370 12 0012 0004 0012
58 | 3371 01 0000 0012 0002
59 | 3372 30 3026 3373 3202
60 | 3373 11 0003 0011 0003
61 | 3374 05 0000 0000 0001
62 | 3375 00 0004 0000 0000
63 | 3376 06 3146 3146 3146
64 | 3377 00 0000 0000 0014
--------------------------------------------------------------------------------
/mem/ROM.txt:
--------------------------------------------------------------------------------
1 | 3010 00 0001 0000 0000
2 | 3011 00 0000 0001 0000
3 | 3012 00 0000 0000 0001
4 | 3013 00 0001 0001 0001
5 | 3014 00 0001 0001 0000
6 | 3015 00 0000 0001 0001
7 | 3016 00 0001 0000 0001
8 | 3017 00 0002 0000 0000
9 | 3020 00 0000 0002 0000
10 | 3021 00 0000 0000 0002
11 | 3022 00 7777 0000 0000
12 | 3023 00 0000 7777 0000
13 | 3024 00 0000 0000 7777
14 | 3025 37 0000 0000 0000
15 | 3026 20 0000 0000 0000
16 | 3027 37 0000 7777 7777
17 | 3030 00 7777 7777 7777
18 | 3031 37 7777 0000 7777
19 | 3032 37 7777 7777 0000
20 | 3033 00 7777 0000 7777
21 | 3034 00 0000 7777 7777
22 | 3035 17 7777 7777 7777
23 | 3036 37 7777 7777 7777
24 | 3037 04 6420 2324 1220
25 | 3040 00 0020 0000 0000
26 | 3041 00 0000 0020 0000
27 | 3042 10 0000 0000 0000
28 | 3043 04 0000 0000 0000
29 | 3044 02 0000 0000 0000
30 | 3045 01 0000 0000 0000
31 | 3046 00 2000 0000 0000
32 | 3047 00 0000 0000 0020
33 | 3050 12 0000 0000 0000
34 | 3051 13 0562 0577 3722
35 | 3052 01 4631 4631 4632
36 | 3053 00 1217 2702 4366
37 | 3054 00 0101 4223 3514
38 | 3055 03 1463 1463 1463
39 | 3056 04 6314 6314 6315
40 | 3057 14 6314 6314 6315
41 | 3060 00 0203 0446 7230
42 | 3061 02 4365 6050 7534
43 | 3062 05 0753 4121 7270
44 | 3063 05 0574 6033 3447
45 | 3064 11 0156 5650 1025
46 | 3065 05 7055 2615 4264
47 | 3066 14 4417 6652 1042
48 | 3067 12 1371 4066 7116
49 | 3070 13 2404 7463 1772
50 | 3071 11 1715 1642 6202
51 | 3072 16 3765 6134 5604
52 | 3073 06 3041 0514 7521
53 | 3074 12 6770 2505 4243
54 | 3075 05 2525 2525 2525
55 | 3076 01 4760 1366 1043
56 | 3077 06 7455 7305 2237
57 | 3100 01 0000 0000 0003
58 | 3101 26 0012 0000 0000
59 | 3102 11 0002 3050 0002
60 | 3103 10 3047 0002 0004
61 | 3104 12 0003 3045 0003
62 | 3105 01 0004 0003 0003
63 | 3106 12 0004 3047 0004
64 | 3107 02 0002 0004 0002
65 | 3110 12 0002 3045 0002
66 | 3111 27 4001 3102 3146
67 | 3112 01 5712 7226 4561
68 | 3113 02 2346 6040 1441
69 | 3114 03 6616 1114 4322
70 | 3115 13 4252 1661 7650
71 | 3116 01 3020 0000 0005
72 | 3117 05 3070 0002 3123
73 | 3120 12 0002 3070 0002
74 | 3121 01 0005 �011 0005
75 | 3122 05 0000 0000 3117
76 | 3123 12 �011 0005 0004
77 | 3124 02 0005 3020 0006
78 | 3125 12 0006 0005 0005
79 | 3126 11 0002 3042 0002
80 | 3127 02 0002 3042 0006
81 | 3130 01 0002 3042 0002
82 | 3131 12 0006 0002 0002
83 | 3132 11 0002 0002 0006
84 | 3133 12 0002 3043 0002
85 | 3134 26 0003 0000 0000
86 | 3135 01 3112 0000 0003
87 | 3136 11 0003 0006 0003
88 | 3137 01 0003 7113 0003
89 | 3140 27 4001 3136 3141
90 | 3141 11 0003 0002 0003
91 | 3142 11 0003 0004 0003
92 | 3143 11 0005 3042 0005
93 | 3144 02 0003 0005 0003
94 | 3145 11 0003 3051 0003
95 | 3146 32 0000 0000 0000
96 | 3147 11 0002 3067 0002
97 | 3150 06 3035 0002 0002
98 | 3151 05 0000 0000 3153
99 | 3152 11 0002 3067 0002
100 | 3153 11 0002 0002 0004
101 | 3154 26 0004 0000 0000
102 | 3155 01 3172 0000 0003
103 | 3156 11 0003 0004 0003
104 | 3157 01 0003 7173 0003
105 | 3160 27 4001 3156 3161
106 | 3161 11 0003 0002 0003
107 | 3162 32 0000 0000 0000
108 | 3163 01 0000 3035 0003
109 | 3164 12 0002 0003 0004
110 | 3165 02 0004 0003 0004
111 | 3166 11 0004 3042 0004
112 | 3167 01 0003 0004 0003
113 | 3170 05 3047 0004 3164
114 | 3171 32 0000 0000 0000
115 | 3172 00 0004 7553 6722
116 | 3173 20 0231 1146 1443
117 | 3174 00 5063 2127 5453
118 | 3175 25 1256 7405 5264
119 | 3176 14 4417 6651 0101
120 | 3177 20 0000 0000 0001
121 | 3202 06 3025 3044 0004
122 | 3203 01 0000 0004 0005
123 | 3204 11 0002 3201 0002
124 | 3205 11 0002 0002 0006
125 | 3206 12 0006 0005 0005
126 | 3207 02 0004 3044 0004
127 | 3210 01 0004 0005 0005
128 | 3211 05 3044 0004 3206
129 | 3212 02 0005 0002 0005
130 | 3213 11 0002 3042 0002
131 | 3214 12 0002 0005 0002
132 | 3215 01 0002 3043 0003
133 | 3216 32 0000 0000 0000
134 | 3217 05 0002 3042 3221
135 | 3220 06 3035 0002 0002
136 | 3221 05 0002 3043 3237
137 | 3222 06 3042 0002 0002
138 | 3223 01 3026 0000 0005
139 | 3224 12 0002 3241 0002
140 | 3225 06 3035 0002 0002
141 | 3226 11 0002 0002 0004
142 | 3227 26 0004 0000 0000
143 | 3230 01 3172 0000 0003
144 | 3231 11 0003 0004 0003
145 | 3232 01 0003 7173 0003
146 | 3233 27 4001 3231 3234
147 | 3234 11 0003 0002 0003
148 | 3235 14 0005 0003 0003
149 | 3236 32 0000 0000 0000
150 | 3237 01 0000 0000 0005
151 | 3240 04 0000 0000 3224
152 | 3241 04 0000 0000 0001
153 | 3242 02 0000 0000 0004
154 | 3243 05 0000 0000 3245
155 | 3244 01 0000 0000 0004
156 | 3245 01 0000 0000 0003
157 | 3246 01 3042 0000 0006
158 | 3247 11 0002 0002 0005
159 | 3250 31 0002 3251 3253
160 | 3251 02 0005 3042 0002
161 | 3252 05 0000 0000 3255
162 | 3253 14 0003 0006 0003
163 | 3254 02 3042 0005 0002
164 | 3255 12 0002 3263 0002
165 | 3256 10 3042 0006 0006
166 | 3257 05 3012 0006 3247
167 | 3260 31 0004 3262 3261
168 | 3261 02 3042 0003 0003
169 | 3262 32 0000 0000 0000
170 | 3263 10 0000 0000 0001
171 | 3264 04 0000 0002 3266
172 | 3265 01 3035 0002 0002
173 | 3266 04 0002 3042 3273
174 | 3267 02 3035 0002 0002
175 | 3270 04 0002 3043 3272
176 | 3271 02 3042 0002 0002
177 | 3272 02 0000 0002 0002
178 | 3273 04 0002 3043 3275
179 | 3274 02 3042 0002 0002
180 | 3275 12 0002 3241 0002
181 | 3276 04 0000 0000 3153
182 | 3277 22 0003 0003 3146
--------------------------------------------------------------------------------
/mem/magnetic_drum.txt:
--------------------------------------------------------------------------------
1 | 0 0 0 4095 -687194767360 0 6373376 0
--------------------------------------------------------------------------------
/mem/punc_cards_out.txt:
--------------------------------------------------------------------------------
1 | 68870512651 137623539724 412501458957 5 6 7
--------------------------------------------------------------------------------
/mem/punched_tape.txt:
--------------------------------------------------------------------------------
1 | 01000000120015
2 | 12001700150016
3 | 02001600150016
4 | 11001600130016
5 | 01001500160015
6 | 05001400160003
7 | 32000000000000
8 | 1099511627775
9 | 549755813888
10 | 16
11 | 219902328832
12 | 16
13 | 43980464128
14 |
--------------------------------------------------------------------------------
/src/asm_disasm.cpp:
--------------------------------------------------------------------------------
1 | // This is a personal academic project. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 |
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "kyiv.h"
10 | #include "asm_disasm.h"
11 |
12 | #define COMMAND_SIZE 4
13 |
14 | constexpr char outputf[] = "../punched_tape.txt";
15 |
16 | std::map en_instructions = {
17 | {"add", "01"},
18 | {"sub", "02"},
19 | {"addcmd", "03"},
20 | {"suba", "06"},
21 | {"addcyc", "07"},
22 | {"mul", "10"},
23 | {"rmul", "11"},
24 | {"div", "12"},
25 | {"sh", "13"},
26 | {"and", "15"},
27 | {"or", "14"},
28 | {"xor", "17"},
29 | {"norm", "35"},
30 | {"jle", "04"},
31 | {"jlea", "05"},
32 | {"je", "16"},
33 | {"nfork", "30"},
34 | {"ncall", "31"},
35 | {"ret", "32"},
36 | {"gob", "26"},
37 | {"goe", "27"},
38 | {"fop", "34"},
39 | {"rdt", "20"},
40 | {"rbn", "21"},
41 | {"wbn", "22"},
42 | {"wmd", "23"},
43 | {"rmd", "24"},
44 | {"imd", "25"},
45 | {"ostanov", "33"}
46 | };
47 |
48 | std::map ua_instructions = {
49 | {"дод", "01"},
50 | {"від", "02"},
51 | {"обк", "03"},
52 | {"авід", "06"},
53 | {"цдод", "07"},
54 | {"множ", "10"},
55 | {"замнож", "11"},
56 | {"діл", "12"},
57 | {"зсв", "13"},
58 | {"і", "15"},
59 | {"або", "14"},
60 | {"вабо", "17"},
61 | {"норм", "35"},
62 | {"кмр", "04"},
63 | {"кмра", "05"},
64 | {"кр", "16"},
65 | {"упп", "30"},
66 | {"упч", "31"},
67 | {"прп", "32"},
68 | {"пго", "26"},
69 | {"кго", "27"},
70 | {"фікс", "34"},
71 | {"чдн", "20"},
72 | {"чбн", "21"},
73 | {"дру", "22"},
74 | {"мбз", "23"},
75 | {"мбч", "24"},
76 | {"мбп", "25"},
77 | {"останов", "33"}
78 | };
79 |
80 | //int disassembly(const uint64_t & command_oct, Kyiv_memory & kmem) {
81 | //
82 | //// std::cout << command_oct << std::endl;
83 | // std::ostringstream str;
84 | // str << std::oct << command_oct;
85 | // std::string command = str.str();
86 | //
87 | // if (command.size() != 13 && command.size() != 14) {
88 | // return -1;
89 | // }
90 | // if (command.size() != 14) {
91 | // command.insert(0, "0");
92 | // }
93 | // std::string result;
94 | // for (const auto & it : en_instructions) {
95 | // if ( it.second == command.substr(0, 2) )
96 | // result.append(it.first);
97 | // }
98 | // if (result.empty()) {
99 | // for (const auto & it : ua_instructions) {
100 | // if ( it.second == command.substr(0, 2) )
101 | // result.append(it.first);
102 | // }
103 | // }
104 | // if (result.empty()) {
105 | // assert("Shouldn't be here!");
106 | // }
107 | // result.append(" " + command.substr(2, 4) + " " + command.substr(6, 4) + " " + command.substr(10, 4));
108 | // word_t Addr_1_mask_shift = (40-6-11)+1;
109 | // word_t Addr_1_mask = 0b11'111'111'111ULL << (Addr_1_mask_shift-1);
110 | // word_t Addr_2_mask_shift = (40-6-12-11)+1;
111 | // word_t Addr_2_mask = 0b11'111'111'111ULL << (Addr_2_mask_shift-1);
112 | // std::string val1 = std::to_string((word_to_number(kmem[(command_oct & Addr_1_mask) >> Addr_1_mask_shift]) )); //* std::pow(2, -40)
113 | // std::string val2 = std::to_string(word_to_number(kmem[(command_oct & Addr_2_mask) >> Addr_2_mask_shift]));
114 | // result.append("\t;; " + val1 + " " + val2);
115 | // std::cout << result << std::endl;
116 | // return 0;
117 | //}
118 |
119 | int disassembly(const uint64_t & command_oct, Kyiv_memory_t & kmem, const addr3_t &addr3) {
120 |
121 | // std::cout << command_oct << std::endl;
122 | std::ostringstream str;
123 | str << std::oct << command_oct;
124 | std::string command = str.str();
125 |
126 | if (command.size() != 13 && command.size() != 14) {
127 | return -1;
128 | }
129 | if (command.size() != 14) {
130 | command.insert(0, "0");
131 | }
132 | std::string result;
133 | for (const auto & it : en_instructions) {
134 | if ( it.second == command.substr(0, 2) )
135 | result.append(it.first);
136 | }
137 | if (result.empty()) {
138 | for (const auto & it : ua_instructions) {
139 | if ( it.second == command.substr(0, 2) )
140 | result.append(it.first);
141 | }
142 | }
143 | if (result.empty()) {
144 | assert("Shouldn't be here!");
145 | }
146 | result.append(" " + command.substr(2, 4) + " " + command.substr(6, 4) + " " + command.substr(10, 4));
147 | word_t Addr_1_mask_shift = (40-6-11)+1;
148 | word_t Addr_1_mask = 0b11'111'111'111ULL << (Addr_1_mask_shift);
149 | word_t Addr_2_mask_shift = (40-6-12-11)+1;
150 | word_t Addr_2_mask = 0b11'111'111'111ULL << (Addr_2_mask_shift);
151 | // std::cout << "NUM : " << std::bitset<41>(command_oct) << std::endl;
152 | // std::cout << "TRUE : " << std::bitset<41>(0'11'0002'3067'0002ULL) << std::endl;
153 | std::string val1 = std::to_string((word_to_number(kmem.read_memory(addr3.source_1)) )) + " " +
154 | std::to_string(word_to_number(kmem.read_memory(addr3.source_1)) * std::pow(2, -40)); //* std::pow(2, -40)
155 | std::string val2 = std::to_string(word_to_number(kmem.read_memory(addr3.source_2))) + " " +
156 | std::to_string(word_to_number(kmem.read_memory(addr3.source_2)) * std::pow(2, -40) );
157 | result.append("\t;; " + val1 + "\t" + val2);
158 | std::cout << result << std::endl;
159 | addr_t a = (command_oct & Addr_2_mask) >> Addr_2_mask_shift;
160 | // std::cout << "TRUE : " << std::bitset<41>(a) << std::endl;
161 | // std::cout << "val2 : " << kmem.read_memory((command_oct & Addr_2_mask) >> Addr_2_mask_shift) << std::endl;
162 | return 0;
163 | }
164 |
165 | int disassembly_text(const std::string file_from, const std::string file_to) {
166 | word_t Addr_1_mask_shift = (40-6-11)+1;
167 | word_t Addr_1_mask = 0b11'111'111'111ULL << (Addr_1_mask_shift-1);
168 | word_t Addr_2_mask_shift = (40-6-12-11)+1;
169 | word_t Addr_2_mask = 0b11'111'111'111ULL << (Addr_2_mask_shift-1);
170 | word_t oct_command;
171 | std::map program;
172 | std::map jumps;
173 | size_t jump_counter = 0;
174 |
175 | std::ifstream infile(file_from);
176 |
177 | std::string line;
178 |
179 | while (std::getline(infile, line)) {
180 | line.erase(remove_if(line.begin(), line.end(), isspace), line.end());
181 | std::ostringstream str;
182 | str << std::oct << line;
183 | std::string command = str.str();
184 | std::string address = command.substr(0, 4);
185 | command = command.substr(4);
186 |
187 | if (command.size() != 13 && command.size() != 14) {
188 | return -1;
189 | }
190 | if (command.size() != 14) {
191 | command.insert(0, "0");
192 | }
193 | std::string result;
194 |
195 | if (command.substr(0, 2) == "00") {
196 | program[address] = command;
197 | continue;
198 | }
199 |
200 | for (const auto &it: en_instructions) {
201 | if (it.second == command.substr(0, 2)) {
202 | result.append(it.first + " ");
203 | std::string addr_1 = command.substr(2, 4) + " ";
204 | std::string addr_2 = command.substr(6, 4) + " ";
205 | std::string addr_3 = command.substr(10, 4) + " ";
206 | std::string mod = mod_comment(addr_1, addr_2, addr_3);
207 |
208 | if (it.first == "jle" || it.first == "jlea" || it.first == "je" || it.first == "ncall" ||
209 | it.first == "gob") {
210 | std::string label = "jump" + std::to_string(jump_counter++);
211 | jumps[addr_3.substr(0, 4)] = label + ":";
212 |
213 | result.append(addr_1);
214 | result.append(addr_2);
215 | result.append(label + " ");
216 | } else if (it.first == "nfork" || it.first == "goe") {
217 | std::string label_1 = "jump" + std::to_string(jump_counter++);
218 | std::string label_2 = "jump" + std::to_string(jump_counter++);
219 | jumps[addr_2.substr(0, 4)] = label_1 + ":";
220 | jumps[addr_3.substr(0, 4)] = label_2 + ":";
221 |
222 | result.append(addr_1);
223 | result.append(label_1 + " ");
224 | result.append(label_2 + " ");
225 | } else {
226 | result.append(addr_1);
227 | result.append(addr_2);
228 | result.append(addr_3);
229 | }
230 |
231 | if (mod != ";") {
232 | result.append("\t" + mod);
233 | }
234 | }
235 | // if (result.empty()) {
236 | // for (const auto &it: ua_instructions) {
237 | // if (it.second == command.substr(0, 2))
238 | // result.append(it.first);
239 | // }
240 | // }
241 | if (result.empty()) {
242 | assert("Shouldn't be here!");
243 | }
244 | program[address] = result;
245 | }
246 | }
247 | disassembler_second_pass(program, jumps, file_to);
248 | return 0;
249 | }
250 |
251 | int disassembler_second_pass(std::map program, std::map jumps, const std::string& file_to) {
252 | std::string prog_to_file = "";
253 | int last_address = std::stoi(program.begin()->first, 0, 8);
254 | int origin_counter = 1;
255 | prog_to_file.append("org0 " + program.begin()->first + "\n");
256 |
257 | for(const auto & it : program) {
258 | if(jumps.find(it.first) != jumps.end()) {
259 | prog_to_file.append(jumps.find(it.first)->second + "\n");
260 | }
261 | if (std::stoi(it.first, 0, 8) - last_address > 1) {
262 | prog_to_file.append("org" + std::to_string(origin_counter++) + " " + it.first + "\n");
263 | }
264 | last_address = std::stoi(it.first, 0, 8); // not sure if I should initialize a new variable for this or leave it like that
265 |
266 | prog_to_file.append("\t" + it.second + "\n");
267 | }
268 |
269 | std::ofstream infile(file_to);
270 | if (!infile.is_open())
271 | return -1;
272 | infile << prog_to_file;
273 | infile.close();
274 |
275 | return 0;
276 | }
277 |
278 |
279 | int check_modification(std::string addr) {
280 | word_t mod_bit = 0b100'000'000'000ULL;
281 | int num = std::stoi(addr, 0, 8);
282 |
283 | if (num & mod_bit) {
284 | return num^mod_bit;
285 | }
286 | return -1;
287 | }
288 |
289 | std::string mod_comment(std::string addr_1, std::string addr_2, std::string addr_3) {
290 | std::string comment = ";";
291 | int check = check_modification(addr_1);
292 |
293 | if (check != -1) {
294 | std::ostringstream str;
295 | str << std::oct << check;
296 | std::string to_print_1 = str.str();
297 | comment.append(" Addr 1: " + to_print_1 + " + A; ");
298 | }
299 |
300 | check = check_modification(addr_2);
301 |
302 | if (check != -1) {
303 | std::ostringstream str;
304 | str << std::oct << check;
305 | std::string to_print_1 = str.str();
306 | comment.append(" Addr 2: " + to_print_1 + " + A; ");
307 | }
308 |
309 | check = check_modification(addr_3);
310 |
311 | if (check != -1) {
312 | std::ostringstream str;
313 | str << std::oct << check;
314 | std::string to_print_1 = str.str();
315 | comment.append(" Addr 3: " + to_print_1 + " + A; ");
316 | }
317 | return comment;
318 | }
319 |
320 | class Assembly {
321 | /*
322 | * Class for reading and executing assembly code on Kyiv.
323 | */
324 | private:
325 | std::map references; // contains origins, labels
326 | std::vector readers; // helper for executing final code on Kyiv
327 | std::vector lines_cout; // Optional - saves command address
328 | size_t command_count; // helper to save current command address
329 | size_t org_counter; // helper to numerate origin
330 | size_t end; // helper to find address of last command
331 | bool text; // check if we input command or value
332 | bool numer; // Optional - if we want to address commands
333 |
334 | public:
335 | /*
336 | * Read file in assembly code, convert it into Kyiv code and write into output file.
337 | * If numerate set in true -- output file will contain commands numeration.
338 | * @param input filename as string, flag to indicate if we address commands as bool
339 | * @return 0 if success
340 | */
341 | int read_file(const std::string& filename, bool numerate=false) {
342 | references = {};
343 | readers = {};
344 | command_count = 0;
345 | org_counter = 0;
346 | numer = numerate;
347 |
348 | std::ifstream infile(filename);
349 | std::string line;
350 | std::vector commands;
351 |
352 | while (std::getline(infile, line)) {
353 | if (line.find(';') != std::string::npos)
354 | line.erase(line.find_first_of(';')); // remove comment
355 | if (!line.empty() && find_special_bts(line) == 0) {
356 | commands.push_back(line);
357 | if (numer) {
358 | std::ostringstream oct;
359 | oct << std::setw(4) << std::setfill('0') << std::oct << command_count;
360 | lines_cout.insert(lines_cout.begin(), oct.str());
361 | command_count++;
362 | }
363 | end++;
364 | }
365 | }
366 | std::ostringstream oct;
367 | oct << std::setw(4) << std::setfill('0') << std::oct << end;
368 | references["org" + std::to_string(org_counter-1)] += oct.str() + "0000";
369 | infile.close();
370 | std::string res;
371 | for (auto & command : commands) {
372 | std::vector argv;
373 | boost::split(argv,command,boost::is_any_of(" "), boost::algorithm::token_compress_off);
374 | if (references.find(argv[0]) != references.end()) {
375 | readers.push_back(references[argv[0]]);
376 | } else {
377 | if (assembly_command(command, res) == -2) {
378 | res += (numer) ? lines_cout.back()+ "\t" : "";
379 | res += command + "\n";
380 | }
381 | if (numer)
382 | lines_cout.pop_back();
383 | }
384 | }
385 | write_file(outputf, res);
386 | return 0;
387 | }
388 |
389 | /*
390 | * Check if we have any helper in line, such as origin, label, text or data section
391 | * @param input line as string
392 | * @return 0 if success
393 | */
394 | int find_special_bts(std::string &line) {
395 | std::vector argv;
396 | boost::algorithm::trim(line);
397 | boost::split(argv,line,boost::is_any_of(" "), boost::algorithm::token_compress_off);
398 | if (argv[0] == ".text"){
399 | text = true;
400 | return 1;
401 | }
402 | else if (argv[0] == ".data") {
403 | text = false;
404 | return 1;
405 | } else if (argv[0] == "org") { // 20/21 start end 0000
406 | if (org_counter != 0) {
407 | std::ostringstream oct;
408 | oct << std::setw(4) << std::setfill('0') << std::oct << end;
409 | references["org" + std::to_string(org_counter-1)] += oct.str() + "0000";
410 | }
411 | end = std::stoi(argv[1], 0, 8) - 1;
412 | std::string com = text ? "21" : "20";
413 | com += argv[1];
414 | if (numer)
415 | command_count = std::stoi(argv[1]);
416 | references["org" + std::to_string(org_counter)] = com;
417 | line = "org" + std::to_string(org_counter++);
418 | } else if (!text && argv.size() == 2) {
419 | std::ostringstream oct;
420 | oct << std::setw(4) << std::setfill('0') << std::oct << end;
421 | references[argv[0]] = oct.str();
422 | line = argv[1];
423 | } else if (!text) {
424 | if (stoi(argv[0]) == 1)
425 | line = "1099511627775";
426 | else
427 | line = std::to_string( (int64_t) (stof(argv[0]) * std::pow(2, 40)));
428 |
429 | } else if (text && argv.size() == 1) {
430 | std::ostringstream oct;
431 | oct << std::setw(4) << std::setfill('0') << std::oct << end;
432 | argv[0].pop_back();
433 | references[argv[0]] = oct.str();
434 | return 1;
435 | }
436 | return 0;
437 | }
438 |
439 | /*
440 | * Check if given line contains command, if yes - convert it into Kyiv code and write into result line
441 | * @param input line as string, result with Kyiv codes as string
442 | * @return 0 if success, -2 if contains data
443 | */
444 | int assembly_command(std::string& command, std::string &result) {
445 | std::vector argv;
446 | boost::split(argv,command,boost::is_any_of(" "), boost::algorithm::token_compress_off);
447 | if (argv.size() != COMMAND_SIZE)
448 | return -2;
449 | for (uint8_t i = 1; i < COMMAND_SIZE; i++) {
450 | if (argv[i].find_first_not_of("01234567") != std::string::npos) {
451 | if (references.find(argv[i]) != references.end()) {
452 | std::cout << command << "\t" << argv[i] << std::endl;
453 | argv[i] = references.find(argv[i])->second;
454 | } else {
455 | return -1;
456 | }
457 | }
458 | if (argv[i].size() != COMMAND_SIZE)
459 | return -1;
460 | }
461 | if (en_instructions.find(argv[0]) != en_instructions.end())
462 | argv[0] = en_instructions[argv[0]];
463 | else if (ua_instructions.find(argv[0]) != ua_instructions.end())
464 | argv[0] = ua_instructions[argv[0]];
465 | else
466 | return -1;
467 | result += (numer && !lines_cout.empty()) ? lines_cout.back() + "\t": "";
468 | result += boost::algorithm::join(argv, "") + "\n";
469 | return 0;
470 | }
471 |
472 | /*
473 | * Write result to given file (punched tape, or perfocard)
474 | * @param file name as pointer to char array, result as string
475 | * @return 0 if success
476 | */
477 | int write_file(const char* filename, std::string &res) {
478 | std::ofstream infile(filename);
479 | if (!infile.is_open())
480 | return -1;
481 | infile << res;
482 | infile.close();
483 | return 0;
484 | }
485 |
486 | /*
487 | * Execute all commands that we convert from assembly into Kyiv codes
488 | * @param struct Kyiv_t, address from which we start execution
489 | * @return 0 if success
490 | */
491 | int execute(Kyiv_t & machine, const size_t start) {
492 | for (auto & i : readers) {
493 | machine.kmem.write_memory(0001, stol(i, 0, 8));
494 | machine.C_reg = 1;
495 | machine.execute_opcode();
496 | }
497 | machine.C_reg = start;
498 | while (machine.execute_opcode()) {
499 | std::cout << "\tRES: " << machine.kmem.read_memory(0015) << " - " << word_to_number(machine.kmem.read_memory(0015)) * std::pow(2, -40) << std::endl;
500 | }
501 | std::cout << "RES: " << machine.kmem.read_memory(0015) << " - " << machine.kmem.read_memory(0015) * std::pow(2, -40) << std::endl;
502 | return 0;
503 | }
504 | };
505 |
506 | int main(int argc, char *argv[]) {
507 | if (argc != 1) {
508 | std::cerr << "Wrong arg" << std::endl;
509 | return -1;
510 | }
511 | // disassembly_text("../ROM.txt", "../rom_k.txt");
512 | // std::cout << std::setprecision(10);
513 | // disassembly_text(outputf, "../h.txt");
514 | // Assembly as;
515 | // as.read_file("../commans.txt", false);
516 | Kyiv_t machine;
517 | machine.kmem.write_memory(00002, 659706976665);
518 | // machine.kmem.write_memory(00010, 659706976665);
519 | // machine.kmem.write_memory(00004, 762123384786);
520 | // machine.kmem.write_memory(00001, 1);
521 | std::cout << machine.kmem.read_memory(03067) << std::endl;
522 | machine.C_reg = 03116;
523 | while (machine.execute_opcode()) {
524 | std::cout << "\tRES 0003: " << word_to_number(machine.kmem.read_memory(00003)) << " - " << word_to_number(machine.kmem.read_memory(00003)) * std::pow(2, -40) << std::endl;
525 |
526 | }
527 |
528 | std::cout << "\tRES 0004: " << word_to_number(machine.kmem.read_memory(00004)) << " - " << word_to_number(machine.kmem.read_memory(00004)) * std::pow(2, -40) << std::endl;
529 |
530 | // as.execute(machine, 2);
531 | // std::string result;
532 | //
533 | // write_file(outputf, result);
534 | //
535 | //
536 | // // machine.kmem[0001] = 0'12'0016'0003'0016ULL;
537 | // machine.kmem[0001] = 0'21'0002'0010'0000ULL;
538 | // machine.kmem[0012] = 549755813888;
539 | // machine.kmem[0013] = 16;
540 | // // machine.kmem[0016] = 9;
541 | // machine.C_reg = 2;
542 | //
543 | //
544 | // while (machine.execute_opcode()) {
545 | // std::cout << "\tRES: " << machine.kmem[0014] << " - " << machine.kmem[0014] * std::pow(2, -40) << std::endl;
546 | // }
547 | // std::cout << "RES: " << machine.kmem[0014] << " - " << machine.kmem[0014] * std::pow(2, -40) << std::endl;
548 | return 0;
549 | }
550 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | // This is a personal academic project. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include "kyiv.h"
16 | #include "asm_disasm.h"
17 | typedef uint64_t addr_t;
18 | typedef uint64_t word_t;
19 | typedef int64_t signed_word_t;
20 | typedef uint32_t opcode_t;
21 | typedef boost::multiprecision::int128_t mul_word_t;
22 |
23 |
24 | constexpr addr3_t word_to_addr3(word_t w){
25 | constexpr word_t Addr_1_mask_shift = (40-6-11)+1;
26 | constexpr word_t Addr_1_mask = 0b11'111'111'111ULL << (Addr_1_mask_shift); // also was -1
27 | constexpr word_t Addr_2_mask_shift = (40-6-12-11)+1;
28 | constexpr word_t Addr_2_mask = 0b11'111'111'111ULL << (Addr_2_mask_shift); // also was -1
29 | constexpr word_t Addr_3_mask_shift = 0; // Для одноманітності
30 | constexpr word_t Addr_3_mask = 0b11'111'111'111ULL;
31 |
32 | addr3_t res;
33 | res.source_1 = (w & Addr_1_mask) >> Addr_1_mask_shift;
34 | res.source_2 = (w & Addr_2_mask) >> Addr_2_mask_shift;
35 | res.destination = (w & Addr_3_mask);
36 | return res;
37 | }
38 |
39 | constexpr opcode_t word_to_opcode(word_t w) {
40 | constexpr word_t op_code_shift = (40-5)+1;
41 | constexpr word_t op_code_mask = 0b11'111ULL << (op_code_shift);
42 | opcode_t opcode = (w & op_code_mask) >> op_code_shift;
43 | return opcode;
44 | }
45 |
46 | static constexpr word_t mask_40_bits = (1ULL << 40) - 1; // 0b111...11 -- 40 1-bits, std::pow(2, 41) === 1 << 41
47 | static constexpr word_t mask_41_bit = (1ULL << 40); // 0b1000...00 -- 40 zeros after the 1
48 |
49 |
50 | constexpr bool is_negative(word_t w){
51 | return w & mask_41_bit; // 0 - додатнє, не нуль -- від'ємне
52 | }
53 |
54 | constexpr word_t to_negative(word_t w){
55 | return w | mask_41_bit;
56 | }
57 |
58 | constexpr word_t to_positive(word_t w){
59 | return w & (~mask_41_bit);
60 | }
61 |
62 | constexpr uint16_t leftmost_one(word_t w){
63 | uint16_t ct = 0;
64 | while (w > 1) {
65 | ct++;
66 | w = w >> 1;
67 | }
68 | return ct;
69 | }
70 |
71 | //hz looks like kostyl but whatever
72 | uint16_t leftmost_one(mul_word_t w){
73 | uint16_t ct = 0;
74 | while (w > 1) {
75 | ct++;
76 | w = w >> 1;
77 | }
78 | return ct;
79 | }
80 |
81 | signed_word_t get_absolute(word_t w){
82 | return static_cast(w & mask_40_bits);
83 | }
84 |
85 | signed_word_t word_to_number(word_t w){
86 | signed_word_t sign1 = (is_negative(w) ? -1 : 1);
87 | signed_word_t abs_val1 = get_absolute(w);
88 | return sign1 * abs_val1;
89 | }
90 |
91 | constexpr bool get_A1(word_t w){
92 | constexpr word_t A_1_mask = 1ULL << (40-5);
93 | return w & A_1_mask;
94 | }
95 |
96 | constexpr bool get_A2(word_t w){
97 | constexpr word_t A_2_mask = 1ULL << (40-5-12);
98 | return w & A_2_mask;
99 | }
100 |
101 | constexpr bool get_A3(word_t w){
102 | constexpr uint64_t A_3_mask = 1ULL << (40-5-24);
103 | return w & A_3_mask;
104 | }
105 |
106 | constexpr addr3_t shift_addr3_byA(addr3_t addr3, uint64_t offset, word_t w){
107 | if(get_A1(w))
108 | addr3.source_1 += offset;
109 | if(get_A2(w))
110 | addr3.source_2 += offset;
111 | if(get_A3(w))
112 | addr3.destination += offset;
113 | return addr3;
114 | }
115 |
116 |
117 | //! Returns: True -- continue, false -- ситуація останову.
118 | bool Kyiv_t::execute_opcode(){
119 | K_reg = kmem.read_memory(C_reg);
120 | std::cout << K_reg << std::endl;
121 | opcode_t opcode = word_to_opcode(K_reg);
122 |
123 | if (opcode == 0) {
124 | ++C_reg;
125 |
126 | }
127 | // std::cout << "opcode: " << opcode << std::endl;
128 | addr3_t addr3 = word_to_addr3(K_reg); // Парі команд потрібна
129 | std::cout << "A_reg_2: " << A_reg << std::endl;
130 | std::cout << "Cycle_reg" << Loop_reg << std::endl;
131 | addr3_t addr3_shifted = shift_addr3_byA(addr3, A_reg, K_reg); // Решта використовують цю змінну
132 |
133 | std::cout << "source 1: " << addr3_shifted.source_1 << std::endl;
134 | std::cout << "source 2: " << addr3_shifted.source_2 << std::endl;
135 |
136 | disassembly(K_reg, kmem, addr3_shifted);
137 | //! Ймовірно, потім це діло треба буде відрефакторити -- відчуваю, но де буде проблема - поки не знаю :+)
138 | switch(opcode){
139 |
140 | //TODO: Тестував лише opcode_add !!! -- решта вважайте невірними, поки не буде тестів. opcode_div
141 | case arythm_operations_t::opcode_div: [[fallthrough]];
142 | case arythm_operations_t::opcode_norm: [[fallthrough]];
143 | case arythm_operations_t::opcode_add: [[fallthrough]];
144 | case arythm_operations_t::opcode_sub: [[fallthrough]];
145 | case arythm_operations_t::opcode_addcmd: [[fallthrough]];
146 | case arythm_operations_t::opcode_subabs: [[fallthrough]];
147 | case arythm_operations_t::opcode_mul: [[fallthrough]];
148 | case arythm_operations_t::opcode_addcyc: [[fallthrough]];
149 | case arythm_operations_t::opcode_mul_round:
150 | opcode_arythm(addr3_shifted, opcode);
151 | break;
152 | //==========================================================================================================
153 | case flow_control_operations_t::opcode_jmp_less_or_equal: [[fallthrough]];
154 | case flow_control_operations_t::opcode_jmp_abs_less_or_equal: [[fallthrough]];
155 | case flow_control_operations_t::opcode_jmp_equal: [[fallthrough]];
156 | case flow_control_operations_t::opcode_fork_negative: [[fallthrough]];
157 | case flow_control_operations_t::opcode_call_negative: [[fallthrough]];
158 | case flow_control_operations_t::opcode_ret: [[fallthrough]];
159 | case flow_control_operations_t::opcode_group_op_begin: [[fallthrough]];
160 | case flow_control_operations_t::opcode_group_op_end: [[fallthrough]];
161 | case flow_control_operations_t::opcode_F: [[fallthrough]];
162 | case flow_control_operations_t::opcode_stop:
163 | opcode_flow_control(addr3_shifted, opcode, addr3);
164 | break;
165 | //==========================================================================================================
166 | case logic_operations_t::opcode_log_shift:{
167 | //! TODO: Мені не повністю зрозуміло з обох книг, величина зсуву береться із RAM за адресою,
168 | //! чи закодована в команді? Швидше перше -- але перевірити!
169 | word_t shift = kmem.read_memory(addr3_shifted.source_1) ; // Глушко-Ющенко, стор 12, сверджує: "на число разрядов,
170 | // равное абсолютной величине константы сдвига, размещаемой в шести младших разрядах ячейки а1"
171 | // 2^6 -- 64, тому решта бітів справді просто дадуть нуль на виході, але все рівно маскую, щоб
172 | // не було невизначеної поведінки С. Та й зразу знак викидаємо
173 | std::cout << "shift: " << shift << std::endl;
174 | shift &= 0b111'111;
175 | std::cout << "shift after some and: " << shift << std::endl;
176 | if(is_negative(kmem.read_memory(addr3_shifted.source_1))) {
177 | kmem.write_memory(addr3_shifted.destination, kmem.read_memory(addr3_shifted.source_2) >> shift);
178 | } else {
179 | kmem.write_memory(addr3_shifted.destination , kmem.read_memory(addr3_shifted.source_2) << shift);
180 | kmem.write_memory(addr3_shifted.destination, kmem.read_memory(addr3_shifted.destination) & (mask_40_bits | mask_41_bit)); // Зануляємо зайві біти
181 | }
182 | ++C_reg;
183 | }
184 | break;
185 | case logic_operations_t::opcode_log_or:{
186 | kmem.write_memory(addr3_shifted.destination, kmem.read_memory(addr3_shifted.source_1) | kmem.read_memory(addr3_shifted.source_2));
187 | ++C_reg;
188 | std::cout << "orr" << kmem.read_memory(addr3_shifted.destination) << std::endl;
189 | }
190 | break;
191 | case logic_operations_t::opcode_log_and:{
192 |
193 | kmem.write_memory(addr3_shifted.destination, kmem.read_memory(addr3_shifted.source_1) & kmem.read_memory(addr3_shifted.source_2));
194 |
195 | ++C_reg;
196 | }
197 | break;
198 | case logic_operations_t::opcode_log_xor:{
199 | kmem.write_memory(addr3_shifted.destination, kmem.read_memory(addr3_shifted.source_1) ^ kmem.read_memory(addr3_shifted.source_2));
200 | ++C_reg;
201 | }
202 | break;
203 | //==========================================================================================================
204 | case IO_operations_t::opcode_read_perfo_data:{
205 | std::ifstream punch_cards;
206 | std::string line;
207 | std::string perfo;
208 | std::vector argv;
209 | signed_word_t number;
210 |
211 | punch_cards.open("../../mem/punch_cards_in.txt");
212 |
213 | int counter = 0;
214 | int num_counter = 0;
215 | bool flag;
216 |
217 | while (punch_cards) {
218 | std::getline(punch_cards, line);
219 | if (counter == perfo_num) {
220 | perfo = line.substr(addr3_shifted.destination, line.size());
221 | boost::split(argv, perfo, boost::is_any_of(" "), boost::algorithm::token_compress_off);
222 | for(auto num : argv){
223 | if(num_counter == addr3_shifted.source_2 - addr3_shifted.source_1){
224 | flag = true;
225 | break;
226 | }
227 | number = std::stol(num);
228 | if(number >= 0){
229 | kmem.write_memory(addr3_shifted.source_1 + num_counter, number);
230 | }else{
231 | kmem.write_memory(addr3_shifted.source_1 + num_counter, to_negative(std::abs(number)));
232 | }
233 | num_counter++;
234 | }
235 | }else if(counter > num_counter){
236 | perfo = line;
237 | boost::split(argv, perfo, boost::is_any_of(" "), boost::algorithm::token_compress_off);
238 | for(auto num : argv){
239 | if(num_counter == addr3_shifted.source_2 - addr3_shifted.source_1){
240 | flag = true;
241 | break;
242 | }
243 | number = std::stoi(num);
244 | if (number >= 0) {
245 | kmem.write_memory(addr3_shifted.source_1 + num_counter, number);
246 | } else {
247 | kmem.write_memory(addr3_shifted.source_1 + num_counter, to_negative(std::abs(number)));
248 | }
249 | num_counter ++;
250 | }
251 | }
252 | if(flag == true){
253 | break;
254 | }
255 | counter++;
256 | }
257 | punch_cards.close();
258 | }
259 | break;
260 |
261 | case IO_operations_t::opcode_read_perfo_binary:{
262 | std::ifstream punch_cards;
263 | std::ifstream heads;
264 | std::string head;
265 | std::string line;
266 |
267 | punch_cards.open("../punched_tape.txt");
268 | heads.open("../heads.txt");
269 |
270 | std::getline(heads, head);
271 | std::getline(heads, head);
272 | // int num = std::stoi(head);
273 | size_t num = h;
274 | int counter = 0;
275 | int com_counter = 0;
276 | bool flag = false;
277 |
278 | while(punch_cards){
279 | std::getline(punch_cards, line);
280 | int pos = 0;
281 | if(counter == num){
282 | if(com_counter < addr3_shifted.source_2 - addr3_shifted.source_1){
283 | kmem.write_memory(addr3_shifted.source_1 + com_counter, std::stol(line, 0, 8));
284 | com_counter++;
285 | }else{
286 | flag = true;
287 | break;
288 | }
289 | }else if(counter > num){
290 | if(com_counter < addr3_shifted.source_2 - addr3_shifted.source_1){
291 | kmem.write_memory(addr3_shifted.source_1 + com_counter, std::stol(line, 0, 8));
292 | com_counter ++;
293 | }else{
294 | flag = true;
295 | break;
296 | }
297 |
298 | }
299 | if(flag){
300 | break;
301 | }
302 | }
303 | h += com_counter;
304 | }
305 | break;
306 |
307 | case IO_operations_t::opcode_read_magnetic_drum:{
308 | std::ifstream magnetic_drum;
309 | std::string line;
310 | std::string data;
311 | std::vector argv;
312 | signed_word_t number;
313 |
314 | magnetic_drum.open("../../mem/drum_in.txt");
315 |
316 | int counter = 0;
317 | int num_counter = 0;
318 | bool flag;
319 | while (magnetic_drum) {
320 | std::getline(magnetic_drum, line);
321 | if(counter == drum_num_read){
322 | data = line.substr(drum_zone_read, line.size());
323 | boost::split(argv, data, boost::is_any_of(" "), boost::algorithm::token_compress_off);
324 | for(const auto& num : argv){
325 | if(num_counter == addr3_shifted.source_2 - addr3_shifted.source_1){
326 | flag = true;
327 | break;
328 | }
329 | number = std::stoi(num);
330 | if(number >= 0){
331 | kmem.write_memory(addr3_shifted.source_1 + num_counter, number);
332 | }else{
333 | kmem.write_memory(addr3_shifted.source_1 + num_counter, to_negative(std::abs(number)));
334 | }
335 | num_counter ++;
336 | }
337 | }else if(counter > drum_num_read){
338 | data = line;
339 | boost::split(argv, data, boost::is_any_of(" "), boost::algorithm::token_compress_off);
340 | for(const auto& num : argv){
341 | if(num_counter == addr3_shifted.source_2 - addr3_shifted.source_1){
342 | flag = true;
343 | break;
344 | }
345 | number = std::stoi(num);
346 | if(number >= 0){
347 | kmem.write_memory(addr3_shifted.source_1 + num_counter, number);
348 | }else{
349 | kmem.write_memory(addr3_shifted.source_1 + num_counter, to_negative(std::abs(number)));
350 | }
351 | num_counter ++;
352 | }
353 | }
354 | if(flag){
355 | break;
356 | }
357 | counter ++;
358 | }
359 |
360 | magnetic_drum.close();
361 | }
362 | break;
363 |
364 | case IO_operations_t::opcode_write_perfo_binary:{
365 | std::ofstream myfile;
366 | myfile.open("../punc_cards_out.txt");
367 | if (myfile.is_open())
368 | {
369 | for(uint64_t i = 0; i <= addr3_shifted.source_2; i++){
370 | myfile << word_to_number(kmem.read_memory(addr3_shifted.source_1 + i));
371 | myfile << ' ';
372 | }
373 | myfile.close();
374 | }else {
375 | std::cout << "Unable to open file";
376 | }
377 | C_reg = addr3_shifted.destination;
378 | K_reg = kmem.read_memory(C_reg);
379 | }
380 |
381 |
382 | case IO_operations_t::opcode_write_magnetic_drum:{
383 | std::ofstream myfile;
384 | myfile.open("../magnetic_drum.txt");
385 | if (myfile.is_open())
386 | {
387 | for(uint64_t i = 0; i <= addr3_shifted.source_2; i++){
388 | myfile << word_to_number(kmem.read_memory(addr3_shifted.source_1 + i));
389 | myfile << ' ';
390 | }
391 | myfile.close();
392 | }else {
393 | std::cout << "Unable to open file";
394 | }
395 | C_reg = addr3_shifted.destination;
396 | K_reg = kmem.read_memory(C_reg);
397 | }
398 | break;
399 |
400 | case IO_operations_t::opcode_init_magnetic_drum:{
401 | if (addr3_shifted.source_1 == 0) {
402 | drum_num_read = addr3_shifted.source_2;
403 | drum_zone_read = addr3_shifted.destination;
404 | } else if (addr3_shifted.source_1 == 1) {
405 | drum_num_write = addr3_shifted.source_2;
406 | drum_zone_write = addr3_shifted.destination;
407 | }
408 | }
409 | break;
410 | //==========================================================================================================
411 | default:
412 | T_reg = true; // ! TODO: Не пам'ятаю, яка там точно реакція на невідому команду
413 | }
414 | return !T_reg;
415 | }
416 |
417 | void Kyiv_t::opcode_arythm(const addr3_t& addr3, opcode_t opcode){
418 | //! TODO: Додати перевірку на можливість запису. Що робила машина при спробі запису в ПЗП?
419 | //! TODO: Додати перевірку на вихід за границю пам'яті -- воно ніби зациклювалося при тому
420 | //! (зверталося до байта add mod 2^11, в сенсі), але точно не знаю.
421 | signed_word_t sign1 = (is_negative(kmem.read_memory(addr3.source_1)) ? -1 : 1);
422 | signed_word_t sign2 = (is_negative(kmem.read_memory(addr3.source_2)) ? -1 : 1);
423 | std::cout << "sign 2" << sign2 << std::endl;
424 | std::cout << "gfuigfalhf: " << addr3.source_2 << std::endl;
425 | word_t abs_val1 = static_cast(kmem.read_memory(addr3.source_1) & mask_40_bits);
426 | word_t abs_val2 = static_cast(kmem.read_memory(addr3.source_2) & mask_40_bits);;
427 | signed_word_t res = sign1 * (signed_word_t) abs_val1;
428 |
429 | signed_word_t res_for_norm;
430 | mul_word_t res_mul;
431 | uint16_t power = 40 - leftmost_one(abs_val1) -1;
432 |
433 | std::cout << sign1 * (signed_word_t) abs_val1 << "gifhdaflvdjasbh\t" << sign2 * (signed_word_t) abs_val2 << std::endl;
434 | switch(opcode){
435 | case arythm_operations_t::opcode_add:
436 | res += sign2 * (signed_word_t) abs_val2;
437 | break;
438 | case arythm_operations_t::opcode_sub:
439 | res -= sign2 * (signed_word_t) abs_val2;
440 | break;
441 | case arythm_operations_t::opcode_addcmd:
442 | res += (signed_word_t) abs_val2;
443 | break;
444 | case arythm_operations_t::opcode_subabs:
445 | res = (signed_word_t) abs_val1 - (signed_word_t) abs_val2;
446 | break;
447 | case arythm_operations_t::opcode_addcyc:
448 | res += sign2 * (signed_word_t) abs_val2; // Те ж, що і для opcode_add, але подальша обробка інша
449 | break;
450 | case arythm_operations_t::opcode_mul: [[fallthrough]];
451 | case arythm_operations_t::opcode_mul_round:
452 | res_mul = sign1 * (mul_word_t) abs_val1 * sign2 * (mul_word_t) abs_val2;
453 | std::cout << "H : " << res_mul << std::endl;
454 | break;
455 | case arythm_operations_t::opcode_norm: {
456 | res_for_norm = sign1 * (abs_val1 << power);
457 | }
458 | break;
459 | case arythm_operations_t::opcode_div: {
460 | if ((abs_val2 == 0) || (abs_val2 < abs_val1)) {
461 | T_reg = true;
462 | ++C_reg;
463 | return;
464 | }
465 | res_mul = ((mul_word_t) abs_val1 << 40) / (mul_word_t) abs_val2;
466 | // std::cout << "Div " << res_mul << std::endl;
467 | }
468 | break;
469 |
470 | default:
471 | assert(false && "Should never been here!");
472 | }
473 |
474 | if(opcode == arythm_operations_t::opcode_add ||
475 | opcode == arythm_operations_t::opcode_sub ||
476 | opcode == arythm_operations_t::opcode_subabs //! TODO: Я не плутаю, результат може мати знак?
477 | ) {
478 | //! TODO: До речі, а якщо переповнення, воно кінцевий регістр змінювало до останову, чи ні?
479 | // Тут я зробив, ніби ні -- але ХЗ, могло. Щоб точно знати -- треба моделювати на рівні схем ;=) --
480 | // як ви і поривалися. Але це не має бути важливим.
481 | bool is_negative = (res < 0);
482 | if (is_negative)
483 | res = -res;
484 | assert(res >= 0);
485 | if (res & mask_41_bit) { // if sum & CPU1.mask_41_bit == 1 -- overflow to sign bit
486 | T_reg = true;
487 | ++C_reg;
488 | return;
489 | }
490 | kmem.write_memory(addr3.destination, static_cast(res) & mask_40_bits);
491 | // std::cout << -1 * res << std::endl;
492 | if (is_negative)
493 | kmem.write_memory(addr3.destination, kmem.read_memory(addr3.destination) | mask_41_bit);
494 | //! "Нуль, получаемый как разность двух равных чисел, имеет отрицательный знак" -- стор. 13 Глушко-Ющенко, опис УПЧ
495 | if(opcode == arythm_operations_t::opcode_sub && res == 0
496 | && abs_val2 == 0 //! TODO: Моє припущення -- перевірити!
497 | ){
498 | kmem.write_memory(addr3.destination, res | mask_41_bit);
499 | std::cout << "NEGATIVE 0" << (res | mask_41_bit) << std::endl;
500 | }
501 | } else if(opcode == arythm_operations_t::opcode_addcmd){
502 | kmem.write_memory(addr3.destination, static_cast(res) & mask_40_bits);
503 | kmem.write_memory(addr3.destination, kmem.read_memory(addr3.destination) | (kmem.read_memory(addr3.source_2) & mask_41_bit)); // Копіюємо біт знаку з source_2 // edited тут наче так має бути
504 | } else if(opcode == arythm_operations_t::opcode_addcyc){
505 | //! TODO: Вияснити, а як ця команда функціонує.
506 | // "Отличается от обычного сложения лишь тем, что в нем отсутствует блокировка при выходе
507 | // из разполагаемого числа разрядов. Перенос из знакового разряда поступает в младший разряд
508 | // сумматора".
509 | // Питання (нумеруючи біти з 1 до 41):
510 | // 1. Перенос із 40 в 41 біт тут можливий? З фрази виглядає, що так.
511 | // 2. Якщо додавання переносу до молодшого біту виникло переповнення, що далі?
512 | // Так виглядає, що воно не може виникнути, але чи я не помилився? -- не може, десь через переніс буде 0
513 | bool is_negative = (res < 0);
514 | // std::cout << (res) << std::endl;
515 | if (is_negative)
516 | res = -res;
517 | assert(res >= 0);
518 |
519 | // std::cout << std::bitset<41> (res) << std::endl;
520 | if(res & mask_41_bit){
521 | res += 1; // Маємо перенос із знакового біту
522 | }
523 |
524 | kmem.write_memory(addr3.destination, static_cast(res) & mask_40_bits);
525 | if (is_negative)
526 | kmem.write_memory(addr3.destination, kmem.read_memory(addr3.destination) | mask_41_bit);
527 | } else if(opcode == arythm_operations_t::opcode_mul ||
528 | opcode == arythm_operations_t::opcode_mul_round
529 | ) {
530 | bool is_negative = (res_mul < 0);
531 | //std::cout << res_mul << std::endl;
532 | if (is_negative)
533 | res_mul = -res_mul;
534 | assert(res_mul >= 0);
535 |
536 | uint16_t leftmost = leftmost_one(res_mul);
537 |
538 | if (opcode == arythm_operations_t::opcode_mul_round) {
539 | res_mul += 1ULL << 41;
540 | }
541 | res_mul = res_mul >> 40;
542 |
543 | kmem.write_memory(addr3.destination, static_cast(res_mul) & mask_40_bits);
544 | std::cout << "DEBUUUUUUUUG2 " << static_cast(res_mul) << std::endl;
545 | // std::cout << is_negative << std::endl;
546 | if (is_negative)
547 | kmem.write_memory(addr3.destination, kmem.read_memory(addr3.destination) | mask_41_bit);
548 | std::cout << "DEBUUUUUUUUG " << word_to_number(kmem.read_memory(addr3.destination)) << std::endl;
549 | // std::cout << std::bitset<41>(kmem[addr3.destination]) << std::endl;
550 | // std::cout << "Mult res: " << word_to_number(kmem[addr3.destination]) << std::endl;
551 |
552 | } else if (opcode == arythm_operations_t::opcode_norm) {
553 | bool is_negative = (res_for_norm < 0);
554 |
555 | if (is_negative)
556 | res_for_norm = -res_for_norm;
557 | assert(res_for_norm >= 0);
558 | //
559 | // std::cout << "norm_val: " << (res_for_norm) << std::endl;
560 | // std::cout << "norm_power: " << (power) << std::endl;
561 | // std::cout << "norm_val_64: " << std::bitset<64>(res_for_norm) << std::endl;
562 | // std::cout << "norm_val_41: " << std::bitset<41>(res_for_norm) << std::endl;
563 |
564 | kmem.write_memory(addr3.source_2, power);
565 | kmem.write_memory(addr3.destination, static_cast(res_for_norm) & mask_40_bits);
566 | if (is_negative)
567 | kmem.write_memory(addr3.destination, kmem.read_memory(addr3.destination) | mask_41_bit);
568 | //
569 | // std::cout << "norm_val_mem: " << kmem[addr3.destination] << std::endl;
570 | // std::cout << "norm_val_pow: " << kmem[addr3.source_2] << std::endl;
571 | } else if (opcode == arythm_operations_t::opcode_div) {
572 | kmem.write_memory(addr3.destination, static_cast(res_mul) & mask_40_bits);
573 | if ((sign1 * sign2) == -1)
574 | kmem.write_memory(addr3.destination, kmem.read_memory(addr3.destination) | mask_41_bit);
575 | // std::cout << "Div res: " << word_to_number(kmem[addr3.destination]) << std::endl;
576 | }
577 | ++C_reg;
578 | }
579 |
580 |
581 | void Kyiv_t::opcode_flow_control(const addr3_t& addr3_shifted, opcode_t opcode, const addr3_t &addr3){
582 | signed_word_t sign1 = (is_negative(kmem.read_memory(addr3_shifted.source_1)) ? -1 : 1);
583 | signed_word_t sign2 = (is_negative(kmem.read_memory(addr3_shifted.source_2)) ? -1 : 1);
584 | signed_word_t abs_val1 = static_cast(kmem.read_memory(addr3_shifted.source_1) & mask_40_bits);
585 | signed_word_t abs_val2 = static_cast(kmem.read_memory(addr3_shifted.source_2) & mask_40_bits);;
586 |
587 | switch (opcode) {
588 | case flow_control_operations_t::opcode_jmp_less_or_equal: {
589 | if((sign1 * abs_val1) <= (sign2 * abs_val2)){
590 | C_reg = addr3_shifted.destination;
591 | } else {
592 | ++C_reg;
593 | }
594 | }
595 | break;
596 | case flow_control_operations_t::opcode_jmp_abs_less_or_equal: {
597 | // std::cout << "Num1 " << get_absolute(kmem[addr3_shifted.source_1]) << std::endl;
598 | // std::cout << "Num2 " << get_absolute(kmem[addr3_shifted.source_2]) << std::endl;
599 | if (abs_val1 <= abs_val2) {
600 | C_reg = addr3_shifted.destination;
601 | } else {
602 | ++C_reg;
603 | }
604 | }
605 | break;
606 | case flow_control_operations_t::opcode_jmp_equal: {
607 | if( (sign1 * abs_val1) == (sign2 * abs_val2)){
608 | C_reg = addr3_shifted.destination;
609 | } else {
610 | ++C_reg;
611 | }
612 | }
613 | break;
614 | case flow_control_operations_t::opcode_fork_negative: {
615 | if( is_negative(kmem.read_memory(addr3_shifted.source_1)) ){
616 | C_reg = addr3_shifted.destination;
617 | }else{
618 | C_reg = addr3_shifted.source_2;
619 | }
620 | }
621 | break;
622 | case flow_control_operations_t::opcode_call_negative:{
623 | if( is_negative(kmem.read_memory(addr3_shifted.source_1)) ){
624 | P_reg = addr3_shifted.source_2; //! TODO: Згідно тексту стор 342 (пункт 18) Гнеденко-Королюк-Ющенко-1961
625 | //! Глушков-Ющенко, стор 13, УПП не до кінця однозначна -- a1 без штриха, це зрозуміло,
626 | //! але з врахуванням A і біта модифікатора, чи без?
627 | //! Виглядає, що в таблиці на стор 180 -- помилка ('A2 => P -- зайвий штрих точно помилка,
628 | //! чи помилка, що, немає зсуву на А?).
629 | //! Однак, в Гнеденко-Королюк-Ющенко-1961 опкод (32) суперечить опкоду в Глушко-Ющенко.
630 | //! Перевірити!
631 | C_reg = addr3_shifted.destination;
632 | }else{
633 | ++C_reg; //! Тут P_reg не мала б змінювати
634 | }
635 | }
636 | break;
637 | case flow_control_operations_t::opcode_ret:{
638 | C_reg = P_reg;
639 | }
640 | break;
641 | case flow_control_operations_t::opcode_group_op_begin:{
642 | // У книжці Глушков-Ющенко на ст. 14, ймовірно, помилка, бо навіть словами пояснено,
643 | // що береться значення а1 і а2, але разом із тим наголошено, що береться не 'а1 чи 'а2,
644 | // а саме а1 і а2. В кінці цієї книжки та у Гнеденко-Королюк-Ющенко пише,
645 | // ніби беруться значення, тому тут реалізовано саме так.
646 | Loop_reg = addr3_shifted.source_1; //word_to_number(kmem.read_memory(addr3_shifted.source_1));
647 | A_reg = addr3_shifted.source_2; // word_to_number(kmem.read_memory(addr3_shifted.source_2));
648 | if (A_reg == Loop_reg) {
649 | C_reg = addr3_shifted.destination;
650 | } else {
651 | ++C_reg;
652 | }
653 |
654 | std::cout << "A_reg: " << A_reg << std::endl;
655 | }
656 | break;
657 | case flow_control_operations_t::opcode_group_op_end:{
658 | // Такий самий прикол, як з НГО
659 | // not a value
660 | A_reg += addr3.source_1;// word_to_number(kmem.read_memory(addr3_shifted.source_1));
661 | if (A_reg == Loop_reg) {
662 | C_reg = word_to_number(addr3_shifted.destination);
663 | } else {
664 | C_reg = (addr3_shifted.source_2);
665 | }
666 | }
667 | break;
668 | case flow_control_operations_t::opcode_F:{
669 | // Якщо я правильно розібралася з 2 попередними командами, то тут все зрозуміло і немає суперечностей
670 | A_reg = word_to_addr3(kmem.read_memory(addr3_shifted.source_1)).source_2;
671 | word_t res = kmem.read_memory(A_reg);
672 | kmem.write_memory(addr3_shifted.destination, res);
673 | ++C_reg;
674 | }
675 | break;
676 | case flow_control_operations_t::opcode_stop:{ //! TODO: Вона враховує стан кнопки на пульті?
677 | // From Glushkov-Iushchenko p. 55
678 | // If B_tumb == 0 -> neutral mode -> full stop
679 | // If B_tumb > 0 -> just skip one command without full stop
680 | // From Glushkov-Iushchenko pp. 163-164
681 | // If B_tumb == 1 -> stop by 3d address
682 | // If B_tumb == 2 -> stop by command number
683 | // I'm not sure what to do with 1st and 2nd B_tumb (maybe that should be handled in main???)
684 | if (!B_tumb) {
685 | T_reg = true;
686 | ++C_reg;
687 | }
688 | else {
689 | C_reg += 2;
690 | }
691 | }
692 | break;
693 | }
694 | }
695 |
--------------------------------------------------------------------------------