Over the last few days I have completed the soldered version of the MOV16 opcode. The task of the MOV16 opcode is to move the content of a 16-bit wide register into another one. The following VHDL code shows the simulated version of the opcode.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
entity Decoder3to8 is Port ( F : in BIT_VECTOR(2 downto 0); -- 3-Bit Function Code (Input) X : out BIT_VECTOR(7 downto 0); -- 8-Bit State (Output) Started: in BIT -- Is the CPU already running? ); end Decoder3to8; architecture Behavioral of Decoder3to8 is begin -- 000 X(0) <= not(F(0)) and not(F(1)) and not (F(2)) and Started after 1 ns; -- 001 X(1) <= F(0) and not (F(1)) and not (F(2)) and Started after 1 ns; -- 010 X(2) <= not(F(0)) and F(1) and not (F(2)) and Started after 1 ns; -- 011 X(3) <= F(0) and F(1) and not (F(2)) and Started after 1 ns; -- 100 X(4) <= not(F(0)) and not(F(1)) and F(2) and Started after 1 ns; -- 101 X(5) <= F(0) and not(F(1)) and F(2) and Started after 1 ns; -- 110 X(6) <= not(F(0)) and F(1) and F(2) and Started after 1 ns; -- 111 X(7) <= F(0) and F(1) and F(2) and Started after 1 ns; end Behavioral; |
As you can see from the implementation, it generates the necessary control signals to:
- Transfer the data from the source register onto the address bus (Select Control Signals)
- Transfer the data from the address bus into the destination register (Load Control Signals)
In addition the MOV16 opcode has to decode from 3 bits the source and destination register. Here I’m using 2 simple 3-to-8 decoders, which are also simulated with the following VHDL code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
-- --------------------------------------- -- Instruction "MOV16" - Format: 01DDDSSS -- --------------------------------------- -- 01: OpCode -- DDD: Destination Register -- => "000": Register M -- => "001": Register X -- => "010": Register J -- => "011": Register SP -- => "100": Register PC -- => "101": Register BP -- => "110": Register Y -- => "111": Register Z -- SSS: Source Register -- => "000": Register M -- => "001": Register X -- => "010": Register J -- => "011": Register SP -- => "100": Register PC -- => "101": Register BP -- => "110": Register Y -- => "111": Register Z -- Check if we execute the "MOV16" instruction - OpCode "01" instruction_MOV16 <= NegatedInstruction(7) and Instruction(6); -- Decode the destination and source register from the provided instruction DestinationRegisterDecoderMOV16: Decoder3to8 port map(Instruction(5 downto 3), MOV16_DestinationRegister, '1'); SourceRegisterDecoderMOV16: Decoder3to8 port map(Instruction(2 downto 0), MOV16_SourceRegister, '1'); -- Gate the specified register onto the data bus Select_M_To_AddressBus_MOV16 <= instruction_MOV16 and MOV16_SourceRegister(0) and (TimingSignals(4) or TimingSignals(5)); Select_X_To_AddressBus_MOV16 <= instruction_MOV16 and MOV16_SourceRegister(1) and (TimingSignals(4) or TimingSignals(5)); Select_J_To_AddressBus_MOV16 <= instruction_MOV16 and MOV16_SourceRegister(2) and (TimingSignals(4) or TimingSignals(5)); Select_SP_To_AddressBus_MOV16 <= instruction_MOV16 and MOV16_SourceRegister(3) and (TimingSignals(4) or TimingSignals(5)); Select_PC_To_AddressBus_MOV16 <= instruction_MOV16 and MOV16_SourceRegister(4) and (TimingSignals(4) or TimingSignals(5)); Select_BP_To_AddressBus_MOV16 <= instruction_MOV16 and MOV16_SourceRegister(5) and (TimingSignals(4) or TimingSignals(5)); Select_Y_To_AddressBus_MOV16 <= instruction_MOV16 and MOV16_SourceRegister(6) and (TimingSignals(4) or TimingSignals(5)); Select_Z_To_AddressBus_MOV16 <= instruction_MOV16 and MOV16_SourceRegister(7) and (TimingSignals(4) or TimingSignals(5)); -- Load the specified register from the data bus Load_M_From_AddressBus_MOV16 <= instruction_MOV16 and MOV16_DestinationRegister(0) and TimingSignals(4); Load_X_From_AddressBus_MOV16 <= instruction_MOV16 and MOV16_DestinationRegister(1) and TimingSignals(4); Load_J_From_AddressBus_MOV16 <= instruction_MOV16 and MOV16_DestinationRegister(2) and TimingSignals(4); Load_SP_From_AddressBus_MOV16 <= instruction_MOV16 and MOV16_DestinationRegister(3) and TimingSignals(4); Load_PC_From_AddressBus_MOV16 <= instruction_MOV16 and MOV16_DestinationRegister(4) and TimingSignals(4); Load_BP_From_AddressBus_MOV16 <= instruction_MOV16 and MOV16_DestinationRegister(5) and TimingSignals(4); Load_Y_From_AddressBus_MOV16 <= instruction_MOV16 and MOV16_DestinationRegister(6) and TimingSignals(4); Load_Z_From_AddressBus_MOV16 <= instruction_MOV16 and MOV16_DestinationRegister(7) and TimingSignals(4); |
The following picture shows the 4 soldered modules: the two 3-to-8 decoders, and the 2 modules that generate the Select and Load Control signals:
In addition I have on a 5th PCB board the logic which tests for the MOV16 opcode (01DDDSSS), which drives the whole Instruction Decoder. The following picture shows the 5 mounted PCB boards:
The green wires are the timing signals from the state machine (the CPU can be in 8 different states), and the blue wires are the current 8-bit wide instruction to be executed (which gets decoded and executed by the module if it is the MOV16 opcode). The black wires are the power lines (VCC, GND).
With that module in place I’m now already able to prepare a 16-bit wide memory address in a specific register as the following assembly code shows:
1 2 3 |
MOV XL, 10101010b MOV XH, 01010101b MOV M, X |
In that case the 16-bit wide M register holds the memory address, which is then used for the LOAD and STORE opcode to read and write from/to the SRAM memory. That’s now the next step that I want to complete over the next few days. Stay tuned 🙂
Thanks for your time,
-Klaus