def src(self, registerpair: int) -> int: """ Name: Send register control. Function: The 8 bit content of the designated index register pair is sent to the RAM address register at X2 and X3. A subsequent read, write, or I/O operation of the RAM will utilize this address. Specifically, the first 2 bits of the address designate a RAM chip; the second 2 bits designate 1 out of 4 registers within the chip; the last 4 bits designate 1 out of 16 4-bit main memory characters within the register. This command is also used to designate a ROM for a subsequent ROM I/O port operation. The first 4 bits designate the ROM chip number to be selected. The address in ROM or RAM is not cleared until the next SRC instruction is executed. The 8 bit content of the index register is unaffected. Syntax: SRC Assembled: 0010 RRR1 Symbolic: (RRRO) --> DB (X2) (RRR1) --> DB (X3) Execution: 1 word, 8-bit code and an execution time of 10.8 usec.. Side-effects: Not Applicable """ from hardware.suboperation import decimal_to_binary if registerpair > 7: raise InvalidRegisterPair('Register pair : ' + str(registerpair)) self.increment_pc(1) address = self.read_registerpair(registerpair) self.COMMAND_REGISTER = decimal_to_binary(8, address) return address
def test_validate_instruction(register): """Ensure instruction's characteristics are valid.""" chip_test = Processor() # Validate the instruction's opcode and characteristics: op = chip_test.INSTRUCTIONS[176 + register] known = { "opcode": 176 + register, "mnemonic": "xch(" + str(register) + ")", "exe": 10.8, "bits": ["1011", decimal_to_binary(4, register)], "words": 1 } # noqa assert op == known
def test_validate_instruction(value): """Ensure instruction's characteristics are valid.""" chip_test = Processor() # Validate the instruction's opcode and characteristics: op = chip_test.INSTRUCTIONS[49 + (value * 2)] known = { "opcode": 49 + (value * 2), "mnemonic": "jin(" + str(value) + ")", "exe": 10.8, "bits": ["0011", decimal_to_binary(4, (2 * value) + 1)], "words": 1 } # noqa assert op == known
def test_validate_instruction(registerpair): """Ensure instruction's characteristics are valid.""" chip_test = Processor() # Validate the instruction's opcode and characteristics: op = chip_test.INSTRUCTIONS[48 + (registerpair * 2)] known = { "opcode": 48 + (registerpair * 2), "mnemonic": "fin(" + str(registerpair) + ")", "exe": 21.6, "bits": ["0011", decimal_to_binary(4, registerpair * 2)], "words": 1 } # noqa assert op == known
def test_validate_instruction(increment): """Ensure instruction's characteristics are valid.""" chip_test = Processor() # Validate the instruction's opcode and characteristics: op = chip_test.INSTRUCTIONS[192 + increment] known = { "opcode": 192 + increment, "mnemonic": "bbl(" + str(increment) + ")", "exe": 10.8, "bits": ["1100", decimal_to_binary(4, increment)], "words": 1 } # noqa assert op == known
def test_validate_instruction(increment): """Ensure instruction's characteristics are valid.""" chip_test = Processor() # Validate the instruction's opcode and characteristics: op = chip_test.INSTRUCTIONS[80 + increment] known = { "opcode": 80 + increment, "mnemonic": "jms(address12)", "exe": 21.6, "bits": ["0101", decimal_to_binary(4, increment)], "words": 2 } # noqa assert op == known
def test_validate_instruction(value): """Ensure instruction's characteristics are valid.""" chip_test = Processor() # Validate the instruction's opcode and characteristics: op = chip_test.INSTRUCTIONS[64 + value] known = {"opcode": 64 + value, "mnemonic": "jun(address12)", "exe": 21.6, "bits": ["0100", decimal_to_binary(4, value)], "words": 2} # noqa assert op == known
def test_validate_instruction(value): """Ensure instruction's characteristics are valid.""" chip_test = Processor() # Validate the instruction's opcode and characteristics: op = chip_test.INSTRUCTIONS[112 + value] known = {"opcode": 112 + value, "mnemonic": "isz(" + str(value) + ",address8)", "exe": 10.8, "bits": ["0111", decimal_to_binary(4, value)], "words": 2} # noqa assert op == known
def wpm(self) -> Tuple[int, int]: """ Name: Write program RAM. Function: This is a special instruction which may be used to write the contents of the accumulator into a half byte of program RAM, or read the contents of a half byte of program RAM into a ROM input port where it can be accessed by a program. The Carry bit is unaffected. Syntax: WPM Assembled: 1110 0011 Symbolic: (A) --> (PRAM) Execution: 1 word, 8-bit code and an execution time of 10.8 usec. Notes: 1 Two WPM instructions must always appear in close succession; that is, each time one WPM instruction references a half byte of program RAM as indicated by an SRC address, another WPM must access the other half byte before the SRC address is altered. An internal counter keeps track of which half-byte is being accessed. If only one WPM occurs, this counter will be out of sync with the program and errors will occur. In this situation, a RESET pulse must be used to re-initialize the machine. 2 A WPM instruction requires an SRC address to access program RAM. Whenever a WPM is executed, the DATA RAM which happens to correspond to this SRC address will also be written. If data needed later in the program is being held in such a DATA RAM, the programmer must save it elsewhere before executing the WPM instruction. """ chip, register, addr = decode_command_register( decimal_to_binary(8, self.COMMAND_REGISTER), 'DATA_RAM_CHAR') rambank = self.read_current_ram_bank() address = convert_to_absolute_address(self, rambank, chip, register, addr) # Get the value of the WPM Counter wpm_counter = read_wpm_counter(self) # Writing if self.ROM_PORT[14] == 1: # Write enabled, so store if wpm_counter == 'LEFT': value = self.ACCUMULATOR << 4 self.PRAM[address] = value self.RAM[address] = value if wpm_counter == 'RIGHT': value = self.ACCUMULATOR self.RAM[address] = self.RAM[address] + value self.PRAM[address] = self.PRAM[address] + value # Reading if self.ROM_PORT[14] != 1: # read if wpm_counter == 'LEFT': self.ROM_PORT[14] = self.PRAM[address] >> 4 << 4 if wpm_counter == 'RIGHT': self.ROM_PORT[15] = self.PRAM[address] << 4 >> 4 flip_wpm_counter(self) self.increment_pc(1) return self.ROM_PORT[14], self.ROM_PORT[15]
def jcn(self, conditions: int, address: int) -> int: """ Name: Jump conditional. Function: If the designated condition code is true, program control is transferred to the instruction located at the 8 bit address AAAA2, AAAA1 on the same page (ROM) where JCN is located. If the condition is not true the next instruction in sequence after JCN is executed. The condition bits are assigned as follows: C1 = 0 Do not invert jump condition } C1 = 1 Invert jump condition } C2 = 1 Jump if the accumulator content is zero C3 = 1 Jump if the carry/link content is 1 C4 = 1 Jump if test signal (pin 10 on 4004) is zero. Syntax: JCN Assembled: 0001 C1C2C3C4 AAAA2 AAAA1 Symbolic: If C1C2C3C4 is true, A2A2A2A2 --> PM A1A1A1A1 --> PL, PH unchanged if C1C2C3C4 is false, (PH) --> PH, (PM) --> PM, (PL + 2) --> PL Execution: 2 words, 16-bit code and an execution time of 21.6 usec. Sample: OPR OPA 0001 0110 Jump if accumulator is zero or carry = 1 Several conditions can be tested simultaneously. The logic equation describing the condition for a jump is give below: JUMP = ~C1 . ((ACC = 0) . C2 + (CY = 1) . C3 + ~TEST . C4) + C1 . ~((ACC != 0) . C2 + (CY = 1) . C3 + ~TEST . C4) +---------+---------+ | Symbol | Logical | +---------+---------+ | ~ + NOT + | . + AND + | + + OR + +---------+---------+ Side-effects: Not Applicable Info about signal/test pin 10 on intel4004 https://tams.informatik.uni-hamburg.de/applets/hades/webdemos/80-mcs4/jmp/jmp_test.html Assembler: jcn IACT lbl I - Invert other conditions A - Accumulator = 0 C - Carry Bit set (i.e. = 1) T - Test Signal on Intel4004 Pin 10 = 0 Need to do "if JCN at end of page" code """ from hardware.suboperations.utility import decimal_to_binary # noqa accumulator = self.read_accumulator() checks = str(decimal_to_binary(4, conditions)) c1 = checks[0:1] == '1' c2 = checks[1:2] == '1' c3 = checks[2:3] == '1' c4 = checks[3:4] == '1' notc1 = True if c1 is False else False notc2 = True if c2 is False else False notc3 = True if c3 is False else False notc4 = True if c4 is False else False # Use symbolic logic to determine whether to jump jump = notc1 and ((accumulator == 0) and c2 or (self.read_carry() == 1) and c3 or (not self.read_pin10()) and c4) or \ c1 and (((accumulator != 0) or notc2) and ((self.read_carry() == 0) or notc3) and ((not self.read_pin10()) or notc4)) if jump is True: self.PROGRAM_COUNTER = address else: self.increment_pc(2) return self.PROGRAM_COUNTER