├── 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 | ![image_1](/img/photo_2022-01-15_04-35-41.jpg)
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 | ![image_2](/img/photo_2022-01-15_04-35-47.jpg)
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 | ![image](https://user-images.githubusercontent.com/50978411/149560770-1e69b03f-a726-4977-bf7f-51dc73fdf1d0.png) 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 | ![image](https://user-images.githubusercontent.com/50978411/149560985-c8facf84-4fe7-4b3a-90f7-4b98925563c2.png) 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 | ![image](https://user-images.githubusercontent.com/50978411/149561110-79695334-4dda-49bd-8e1a-2135b614bfd4.png) 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 | ![image](https://user-images.githubusercontent.com/50978411/149561230-f6c63bc9-6052-4b58-bd3d-e18417d3dccc.png) 212 | 213 | 5. Three magnetic drums 214 | 215 | ![image](https://user-images.githubusercontent.com/50978411/149561296-743bcaf5-944d-4f77-9de5-d18570147177.png) 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 | --------------------------------------------------------------------------------