---
# System prepended metadata

title: TP_PSD9_DanishAlFayyadhSunarta_2406416951

---

# TP Modul 9 - Microprogramming 

> Pembuat Soal: AX

```txt
Nama : Danish Al Fayydh Sunarta
NPM  : 2406416951
```

## Teori (30 pts)

### 1. Jelaskan perbedaan control unit dengan menggunakan microprogramming dan FSM (hardwired) (15 poin)

|poin|microprogramming|FSM (hardwired)|
|:-:|:-:|:-:|
|implementasi|menggunakan pendekatan berbasis memori. control signals disimpan di dalam ROM sebagai microinstructions dan digunakan untuk mengontrol CPU|menggunakan rangkaian logika sekuensial murni yang terdiri dari gerbang logika, flip-flop, dan decoder. control signals bersifat statis karena dihasilkan langsung oleh hardware berdasarkan state saat ini dan input.|
|kecepatan|biasanya lebih lambat karena perlu mengakses momori, sehingga terdapat delay pada saat mengakses microinstructions dan fetching.|biasanya lebih cepat karena tidak perlu mengakses memori.|
|fleksibilitas|untuk mengubah (menambah/mengganti/menghapus) instruksi hanya perlu dilakukan dengan mengubah isi memori|perubahan pada suatu set instruksi memerulukan perancangan ulang pada design keseluruhannya.|

### Referensi

- Geeksforgeeks, “Difference between Hardwired and Micro-programmed Control Unit | Set 2,” Geeksforgeeks, 11 Jul, 2025. [Online]. Available: https://www.geeksforgeeks.org/computer-organization-architecture/difference-between-hardwired-and-micro-programmed-control-unit-set-2/. [Accessed: 16 Nov, 2025].
- unstop, “Hardwired Vs. Microprogrammed Control Unit: Differences & Examples,” unstop. [Online]. Available: https://unstop.com/blog/differences-between-hardwired-control-unit-and-microprogrammed-control-unit. [Accessed: 16 Nov, 2025].

### 2. Apa keuntungan menggunakan microprogramming dibanding dengan FSM (hardwired) (15 poin)

- hanya perlu mengubah isi memori untuk mengubah microinstructions
- rangkaian lebih sederhana untuk instruction set yang besar sehingga biayanya lebih rendah dan lebih mudah untuk di-maintain
- dapat meniru set instruksi dari komputer/perangkat lain

### Referensi

- Geeksforgeeks, “Difference Between Hardwired and Microprogrammed Control Unit,” Geeksforgeeks, 12 Jul, 2025. [Online]. Available: https://www.geeksforgeeks.org/computer-organization-architecture/difference-between-hardwired-and-microprogrammed-control-unit/. [Accessed: 16 Nov, 2025].
- unstop, “Hardwired Vs. Microprogrammed Control Unit: Differences & Examples,” unstop. [Online]. Available: https://unstop.com/blog/differences-between-hardwired-control-unit-and-microprogrammed-control-unit. [Accessed: 16 Nov, 2025].

## Praktik (70 pts)
Buka kembali code LP8 yang kalian kerjakan dan pastikan bahwa semua tabel control wordnya sudah benar (TP + CS) yang berarti total ada 12 instruction : 
- LDA 
- STA
- LDB
- STB
- MAB
- MBA
- NOP
- JMP
- CMP
- ADD
- SUB
- HLT

Sekarang baca kembali daste (jika belum ya baca lah) : 
https://learn.digilabdte.com/books/digital-sistem-design-psddsg/chapter/module-9-microprogramming

### A. Dari sini ubahlah code yang anda kerjakan dari yang tadinya merupakan FSM menjadi bentuk microprogrammingnya (25 pts)

ISI **TODO** : 

```vhdl
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

-- Entity tetap sama persis
entity control_unit is
    port (
        CLK             : in std_logic;
        enable          : in std_logic;
        RST             : in std_logic;
        carry_flag      : in std_logic;
        zero_flag       : in std_logic;
        opcode          : in std_logic_vector(3 downto 0);
        control_signals : out std_logic_vector(13 downto 0) -- [RAO,RAI,RBO,RBI,SUB,ALO,PCI,PCO,CNT,MRI,RMI,RMO,IRI,IRO]
    );
end entity control_unit;

architecture rtl_classic_microprogram of control_unit is

    -- ### 1. Definisi Format Micro-Instruction ###
    
    -- Bit sekuensial (seperti di kode hipotetis Anda)
    constant C_CTRL_BITS : integer := 14; -- 14 bit untuk sinyal kontrol
    constant C_SEQ_BITS  : integer := 2;  -- 2 bit untuk sequencing
    constant C_UCODE_WIDTH : integer := C_CTRL_BITS + C_SEQ_BITS; -- Total 16 bit
    
    -- Perintah sequencing
    constant SEQ_NEXT   : std_logic_vector(1 downto 0) := "00"; -- Ambil uPC + 1
    constant SEQ_DECODE : std_logic_vector(1 downto 0) := "01"; -- Lompat berdasarkan opcode
    constant SEQ_FETCH  : std_logic_vector(1 downto 0) := "10"; -- Kembali ke alamat Fetch (0)
    constant SEQ_HLT    : std_logic_vector(1 downto 0) := "11"; -- Berhenti (loop di uPC)

    -- ### 2. Control Store (ROM) ###

    -- Kita butuh uPC yang lebih besar untuk memetakan alamat
    subtype t_uAddress is unsigned(7 downto 0);
    type t_control_store is array(0 to 255) of std_logic_vector(C_UCODE_WIDTH - 1 downto 0);

    -- Helper function untuk membangun micro-instruction
    function to_ucode(
        ctrl : std_logic_vector(C_CTRL_BITS - 1 downto 0);
        seq  : std_logic_vector(C_SEQ_BITS - 1 downto 0)
    ) return std_logic_vector is
    begin
        -- Format: [Seq(1:0), Ctrl(13:0)]
        return seq & ctrl;
    end function;

    -- Alamat untuk Fetch & Alamat "lompat" untuk Opcode 
    constant uADDR_FETCH1 : t_uAddress := "00000000"; -- Alamat 0
    constant uADDR_FETCH2 : t_uAddress := "00000001"; -- Alamat 1
    constant uADDR_FETCH3 : t_uAddress := "00000010"; -- Alamat 2
    
    -- =============TODO: Definisikan konstanta untuk alamat micro-routine setiap instruksi=============
    -- Buat konstanta uADDR untuk setiap instruksi (NOP, LDA, STA, ADD, MAB, LDB, STB, MBA, JMP, CMP, SUB, HLT)
    -- Format: constant uADDR_XXX1 : t_uAddress := "XXXXXXXX";
    -- Contoh: constant uADDR_NOP1 : t_uAddress := "00010000"; -- Opcode 0000 -> alamat 16
    -- Berikan jarak antar alamat untuk instruksi multi-cycle (jarak 2 untuk tiap instruction)
    -- =================================================================================================
    constant uADDR_NOP1 : t_uAddress := x"10";
    constant uADDR_LDA1 : t_uAddress := x"12";
    constant uADDR_STA1 : t_uAddress := x"14";
    constant uADDR_ADD1 : t_uAddress := x"16";
    constant uADDR_MAB1 : t_uAddress := x"18";
    constant uADDR_LDB1 : t_uAddress := x"1A";
    constant uADDR_STB1 : t_uAddress := x"1C";
    constant uADDR_MBA1 : t_uAddress := x"1E";
    constant uADDR_JMP1 : t_uAddress := x"20";
    constant uADDR_CMP1 : t_uAddress := x"22";
    constant uADDR_SUB1 : t_uAddress := x"24";
    constant uADDR_HLT1 : t_uAddress := x"26";

    -- Inisialisasi ROM
    function init_rom return t_control_store is
        variable rom : t_control_store := (others => (others => '0'));
        
        -- Konstanta 14-bit untuk sinyal kontrol FETCH (sudah lengkap sebagai contoh)
        constant C_FETCH1 : std_logic_vector(13 downto 0) := "00000001010000"; -- PCO=1, MRI=1
        constant C_FETCH2 : std_logic_vector(13 downto 0) := "00000000000110"; -- RMO=1, IRI=1
        constant C_FETCH3 : std_logic_vector(13 downto 0) := "00000000000110"; -- RMO=1, IRI=1
        
        -- =============TODO: Definisikan konstanta 14-bit untuk sinyal kontrol setiap instruksi=============
        -- 
        -- Format konstanta: constant C_XXX1 : std_logic_vector(13 downto 0) := "XXXXXXXXXXXXXX";
        -- 
        -- Untuk bit Control Wordnya ingat kembali TP dan CS dan pastikan sudah benar
        -- ==================================================================================================
        constant C_LDA1 : std_logic_vector(13 downto 0) := "00000000010001"; 
        constant C_LDA2 : std_logic_vector(13 downto 0) := "01000000100100"; 
        
        constant C_STA1 : std_logic_vector(13 downto 0) := "00000000010001";
        constant C_STA2 : std_logic_vector(13 downto 0) := "10000000101000";

        constant C_ADD1 : std_logic_vector(13 downto 0) := "01000100100000";

        constant C_MAB1 : std_logic_vector(13 downto 0) := "10010000100000";

        constant C_LDB1 : std_logic_vector(13 downto 0) := "00000000010001";
        constant C_LDB2 : std_logic_vector(13 downto 0) := "00010000100100";

        constant C_STB1 : std_logic_vector(13 downto 0) := "00000000010001";
        constant C_STB2 : std_logic_vector(13 downto 0) := "00100000101000";

        constant C_MBA1 : std_logic_vector(13 downto 0) := "01100000100000";

        constant C_JMP1 : std_logic_vector(13 downto 0) := "00000010000001";

        constant C_CMP1 : std_logic_vector(13 downto 0) := "00001000100000";

        constant C_SUB1 : std_logic_vector(13 downto 0) := "01001100100000";

        constant C_NOP1 : std_logic_vector(13 downto 0) := "00000000100000";

        constant C_HLT1 : std_logic_vector(13 downto 0) := "00000000000000";

    begin
        -- ### Siklus Fetch (3 cycles) - SORRY INI HARUSNYA BEGINI ###
        rom(to_integer(uADDR_FETCH1)) := to_ucode(C_FETCH1, SEQ_NEXT);   -- CC1: PCO=1, MRI=1 -> lanjut ke FETCH2
        rom(to_integer(uADDR_FETCH2)) := to_ucode(C_FETCH2, SEQ_NEXT);   -- CC2: RMO=1, IRI=1 -> lanjut ke FETCH3
        rom(to_integer(uADDR_FETCH3)) := to_ucode(C_FETCH3, SEQ_DECODE); -- CC3: RMO=1, IRI=1 -> decode opcode
        
        -- ===========TODO: Isi ROM dengan micro-routines untuk setiap instruksi=============
        -- 
        -- Gunakan fungsi to_ucode(control_signal_constant, sequencing_command)
        -- - Parameter 1: Konstanta control signal (misal C_NOP1, C_LDA1, dll)
        -- - Parameter 2: Perintah sequencing (SEQ_NEXT, SEQ_FETCH, SEQ_DECODE, atau SEQ_HLT)
        -- 
        -- Sequencing command menentukan kemana uPC akan melompat setelah cycle ini:
        -- - SEQ_NEXT   : Lanjut ke alamat berikutnya (uPC + 1)
        -- - SEQ_FETCH  : Kembali ke awal FETCH (uADDR_FETCH1)
        -- - SEQ_DECODE : Decode opcode dan lompat ke instruksi yang sesuai
        -- - SEQ_HLT    : Berhenti, tetap di alamat yang sama (loop forever)
        -- 
        -- Ini akan mirip dengan state machine pada modul sebelumnya, tapi di sini kita hanya mengisi ROM
        -- dengan micro-instructions yang sesuai untuk setiap instruksi.
        -- Kalo bingung liat yang fetch kayak gimana ngisinya.
        -- ====================================================================================
        rom(to_integer(uADDR_NOP1)) := to_ucode(C_NOP1, SEQ_FETCH);

        rom(to_integer(uADDR_LDA1))     := to_ucode(C_LDA1, SEQ_NEXT); 
        rom(to_integer(uADDR_LDA1) + 1) := to_ucode(C_LDA2, SEQ_FETCH); 

        rom(to_integer(uADDR_STA1))     := to_ucode(C_STA1, SEQ_NEXT);
        rom(to_integer(uADDR_STA1) + 1) := to_ucode(C_STA2, SEQ_FETCH);

        rom(to_integer(uADDR_ADD1)) := to_ucode(C_ADD1, SEQ_FETCH);

        rom(to_integer(uADDR_MAB1)) := to_ucode(C_MAB1, SEQ_FETCH);

        rom(to_integer(uADDR_LDB1))     := to_ucode(C_LDB1, SEQ_NEXT);
        rom(to_integer(uADDR_LDB1) + 1) := to_ucode(C_LDB2, SEQ_FETCH);

        rom(to_integer(uADDR_STB1))     := to_ucode(C_STB1, SEQ_NEXT);
        rom(to_integer(uADDR_STB1) + 1) := to_ucode(C_STB2, SEQ_FETCH);

        rom(to_integer(uADDR_MBA1)) := to_ucode(C_MBA1, SEQ_FETCH);

        rom(to_integer(uADDR_JMP1)) := to_ucode(C_JMP1, SEQ_FETCH);

        rom(to_integer(uADDR_CMP1)) := to_ucode(C_CMP1, SEQ_FETCH);

        rom(to_integer(uADDR_SUB1)) := to_ucode(C_SUB1, SEQ_FETCH);

        rom(to_integer(uADDR_HLT1)) := to_ucode(C_HLT1, SEQ_HLT);
        return rom;
    end function;

    -- Buat ROM
    constant Control_Store : t_control_store := init_rom;

    -- ### 3. Sinyal Internal ###
    
    -- Micro-Program Counter (uPC)
    signal uPC     : t_uAddress := uADDR_FETCH1;
    signal Next_uPC : t_uAddress;
    
    -- Micro-Instruction Register (uIR)
    signal uIR : std_logic_vector(C_UCODE_WIDTH - 1 downto 0);
    
begin

    -- ### PROSES 1: uPC Register (State Register) ###
    uPC_REGISTER: process(CLK) is
    begin
        if enable = '1' and rising_edge(CLK) then
            if RST = '1' then
                uPC <= uADDR_FETCH1; -- Reset kembali ke Fetch (alamat 0)
            else
                uPC <= Next_uPC;
            end if;
        end if;
    end process uPC_REGISTER;

    -- ### PROSES 2: Pembacaan ROM (Moore) ###
    -- Baca micro-instruction dari ROM berdasarkan uPC saat ini
    uIR <= Control_Store(to_integer(uPC));

    -- ### PROSES 3: Sequencer Logic (Menentukan uPC Berikutnya) ###
    -- Ini adalah "otak" yang "bodoh" dari kode hipotetis Anda.
    SEQUENCER_LOGIC: process(uPC, uIR, opcode, carry_flag, zero_flag)
        variable seq_control : std_logic_vector(1 downto 0);
    begin
        -- Ekstrak 2 bit sequencing dari micro-instruction saat ini
        seq_control := uIR(C_UCODE_WIDTH - 1 downto C_CTRL_BITS);
        
        -- Default: selalu increment (untuk jaga-jaga)
        Next_uPC <= uPC + 1;

        case seq_control is
            when SEQ_NEXT =>
                -- Perintah: Ambil micro-instruction berikutnya secara berurutan
                Next_uPC <= uPC + 1;
                
            when SEQ_FETCH =>
                -- Perintah: Kembali ke awal siklus Fetch
                Next_uPC <= uADDR_FETCH1;

            when SEQ_HLT =>
                -- Perintah: Berhenti! Tetap di alamat ini selamanya.
                Next_uPC <= uPC; 

            when SEQ_DECODE =>
                -- =============TODO: Implementasikan decoding opcode ke alamat micro-routine=============
                -- Perintah: Lihat opcode dan lompat ke alamat micro-routine yang sesuai
                -- Yaudah, mirip lah yak dengan state machine di modul sebelumnya.
                -- =======================================================================================
                case opcode is
                    when "0000" => Next_uPC <= uADDR_NOP1;
                    when "0001" => Next_uPC <= uADDR_LDA1;
                    when "0010" => Next_uPC <= uADDR_STA1;
                    when "0011" => Next_uPC <= uADDR_ADD1;
                    when "0100" => Next_uPC <= uADDR_MAB1;
                    when "0101" => Next_uPC <= uADDR_LDB1;
                    when "0110" => Next_uPC <= uADDR_STB1;
                    when "0111" => Next_uPC <= uADDR_MBA1;
                    when "1000" => Next_uPC <= uADDR_JMP1;
                    when "1001" => Next_uPC <= uADDR_CMP1;
                    when "1100" => Next_uPC <= uADDR_SUB1;
                    when "1111" => Next_uPC <= uADDR_HLT1;
                    when others => Next_uPC <= uADDR_FETCH1;
                end case;
            when others =>
                -- Pengaman jika terjadi error
                Next_uPC <= uADDR_FETCH1;
        end case;
    end process SEQUENCER_LOGIC;

    -- ### PROSES 4: Output Logic ###
    -- Output-nya hanyalah 14 bit sinyal kontrol dari micro-instruction
    control_signals <= uIR(13 downto 0);

end architecture rtl_classic_microprogram;
```
Codenya dicopas di atas ajah

### B. Tes kode anda dengan testbench di bawah ini (25 pts): 
```vhdl
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

-- This is the entity for the testbench. It's empty.
entity tb_cpu is
end entity tb_cpu;

architecture sim of tb_cpu is

    -- ### 1. Component Declaration ###
    -- This is our "Device Under Test" (DUT), the brain.
    component control_unit is
        port (
            CLK             : in std_logic;
            enable          : in std_logic;
            RST             : in std_logic;
            carry_flag      : in std_logic;
            zero_flag       : in std_logic;
            opcode          : in std_logic_vector(3 downto 0);
            control_signals : out std_logic_vector(13 downto 0)
        );
    end component control_unit;

    -- ### 2. Signal Declarations (The "Wires") ###

    -- Testbench control
    signal s_clk    : std_logic := '0';
    signal s_rst    : std_logic := '0';
    signal s_enable : std_logic := '1';
    constant CLK_PERIOD : time := 10 ns;

    -- Connections to/from the Control Unit
    signal s_carry_flag : std_logic;
    signal s_zero_flag  : std_logic;
    signal s_opcode     : std_logic_vector(3 downto 0);
    signal s_control_signals : std_logic_vector(13 downto 0);
    
    -- ### 3. Datapath Components (as signals) ###

    -- The Main 8-bit Bus
    signal s_bus : std_logic_vector(7 downto 0);

    -- Registers
    signal s_reg_a : std_logic_vector(7 downto 0) := (others => '0'); -- Register A
    signal s_reg_b : std_logic_vector(7 downto 0) := (others => '0'); -- Register B
    signal s_pc    : std_logic_vector(7 downto 0) := (others => '0'); -- Program Counter (8-bit)
    signal s_ir    : std_logic_vector(7 downto 0) := (others => '0'); -- Instruction Register
    signal s_mar   : std_logic_vector(3 downto 0) := (others => '0'); -- Memory Address Register (4-bit)

    -- ALU
    signal s_alu_out : std_logic_vector(7 downto 0); -- ALU's internal output
    
    -- RAM (16 locations, 8 bits wide)
    type t_ram is array (0 to 15) of std_logic_vector(7 downto 0);
    
    -- This is our "Program" and "Data"
    signal s_ram : t_ram := (
        0  => "00011000", -- x"18" Program: LDA 8 (Opcode=0001, Addr=1000)
        1  => "01011001", -- x"59" Program: LDB 9 (Opcode=0101, Addr=1001)
        2  => "00110000", -- x"30" Program: ADD  (Opcode=0011, Addr=0000)
        3  => "01011010", -- x"5A" Program: LDB 10 (Opcode=0101, Addr=1010)
        4  => "11000000", -- x"C0" Program: SUB  (Opcode=1100, Addr=0000)
        5  => "11110000", -- x"F0" Program: HLT  (Opcode=1111, Addr=0000)
        6  => (others => '0'),
        7  => (others => '0'),
        8  => "00001010", -- x"0A" Data: 10
        9  => "00000101", -- x"05" Data: 5
        10 => "00000011", -- x"03" Data: 3
        others => (others => '0')
    );
    
    -- ### 4. Control Signal Aliases (for readability) ###
    -- This makes the code MUCH easier to understand.
    alias s_RAO : std_logic is s_control_signals(13); -- Register A Out
    alias s_RAI : std_logic is s_control_signals(12); -- Register A In
    alias s_RBO : std_logic is s_control_signals(11); -- Register B Out
    alias s_RBI : std_logic is s_control_signals(10); -- Register B In
    alias s_SUB : std_logic is s_control_signals(9);  -- ALU Subtract
    alias s_ALO : std_logic is s_control_signals(8);  -- ALU Out
    alias s_PCI : std_logic is s_control_signals(7);  -- Program Counter In
    alias s_PCO : std_logic is s_control_signals(6);  -- Program Counter Out
    alias s_CNT : std_logic is s_control_signals(5);  -- Program Counter Increment (Count)
    alias s_MRI : std_logic is s_control_signals(4);  -- Memory Register In
    alias s_RMI : std_logic is s_control_signals(3);  -- RAM In (Write)
    alias s_RMO : std_logic is s_control_signals(2);  -- RAM Out (Read)
    alias s_IRI : std_logic is s_control_signals(1);  -- Instruction Register In
    alias s_IRO : std_logic is s_control_signals(0);  -- Instruction Register Out
    
begin

    -- ### 5. Instantiate the "Brain" ###
    UUT_Control_Unit: control_unit
        port map (
            CLK             => s_clk,
            enable          => s_enable,
            RST             => s_rst,
            carry_flag      => s_carry_flag,
            zero_flag       => s_zero_flag,
            opcode          => s_opcode,
            control_signals => s_control_signals
        );

    -- ### 6. Clock and Stimulus ###
    
    -- Clock Generator
    CLK_GEN: process
    begin
        s_clk <= '0'; wait for CLK_PERIOD / 2;
        s_clk <= '1'; wait for CLK_PERIOD / 2;
    end process CLK_GEN;

    -- Stimulus (Reset and Run)
    STIMULUS: process
    begin
        s_rst <= '1';
        wait for CLK_PERIOD * 5; -- Hold reset
        s_rst <= '0';
        wait for CLK_PERIOD * 100; -- Let the simulation run for 100 cycles
        report "Simulation Halted. Check waveforms." severity note;
        wait;
    end process STIMULUS;

    -- ### 7. Datapath Implementation ###

    -- ## The 8-bit Bus (Concurrent Multiplexer) ##
    -- This is the heart of the CPU. It selects who gets to "talk"
    -- on the bus based on the control signals.
    s_bus <= s_alu_out              when s_ALO = '1' else -- ALU Output
             s_reg_a                when s_RAO = '1' else -- Register A Output
             s_reg_b                when s_RBO = '1' else -- Register B Output
             s_pc                   when s_PCO = '1' else -- PC Output
             s_ram(to_integer(unsigned(s_mar))) when s_RMO = '1' else -- RAM Output
             "0000" & s_ir(3 downto 0) when s_IRO = '1' else -- IR LSB Output (for JMP)
             "ZZZZZZZZ"; -- High-Impedance (nothing writing)

    -- Monitor bus conflicts (for debugging)
    BUS_MONITOR: process(s_clk)
        variable driver_count : integer;
    begin
        if rising_edge(s_clk) then
            driver_count := 0;
            if s_ALO = '1' then driver_count := driver_count + 1; end if;
            if s_RAO = '1' then driver_count := driver_count + 1; end if;
            if s_RBO = '1' then driver_count := driver_count + 1; end if;
            if s_PCO = '1' then driver_count := driver_count + 1; end if;
            if s_RMO = '1' then driver_count := driver_count + 1; end if;
            if s_IRO = '1' then driver_count := driver_count + 1; end if;
            
            -- Report bus conflicts
            if driver_count > 1 then
                report "BUS CONFLICT! Multiple drivers active at PC=" & 
                       integer'image(to_integer(unsigned(s_pc))) severity error;
            end if;
        end if;
    end process BUS_MONITOR;

    -- ## Clocked Registers (The "Listeners") ##
    -- These processes describe all the components that load
    -- data from the bus on the rising edge of the clock.

    -- Register A
    REG_A_PROC: process(s_clk)
    begin
        if rising_edge(s_clk) then
            if s_RAI = '1' then
                s_reg_a <= s_bus;
            end if;
        end if;
    end process REG_A_PROC;

    -- Register B
    REG_B_PROC: process(s_clk)
    begin
        if rising_edge(s_clk) then
            if s_RBI = '1' then
                s_reg_b <= s_bus;
            end if;
        end if;
    end process REG_B_PROC;
    
    -- Instruction Register (IR)
    IR_PROC: process(s_clk)
    begin
        if rising_edge(s_clk) then
            if s_IRI = '1' then
                s_ir <= s_bus;
            end if;
        end if;
    end process IR_PROC;

    -- Memory Address Register (MAR)
    MAR_PROC: process(s_clk)
    begin
        if rising_edge(s_clk) then
            if s_MRI = '1' then
                s_mar <= s_bus(3 downto 0); -- Only takes 4 LSB
            end if;
        end if;
    end process MAR_PROC;

    -- Program Counter (PC)
    -- This one is special: it can Reset, Load (for JMP), or Increment
    PC_PROC: process(s_clk)
    begin
        if rising_edge(s_clk) then
            if s_rst = '1' then
                s_pc <= (others => '0');
            elsif s_PCI = '1' then -- Priority 1: Load (JMP)
                s_pc <= s_bus;
            elsif s_CNT = '1' then -- Priority 2: Increment
                s_pc <= std_logic_vector(unsigned(s_pc) + 1);
            end if;
        end if;
    end process PC_PROC;

    -- RAM Write Logic (RMI)
    RAM_WRITE_PROC: process(s_clk)
    begin
        if rising_edge(s_clk) then
            if s_RMI = '1' then
                -- Write data from bus to RAM at address in MAR
                if s_bus /= "ZZZZZZZZ" then
                    s_ram(to_integer(unsigned(s_mar))) <= s_bus;
                end if;
            end if;
        end if;
    end process RAM_WRITE_PROC;

    -- ## Combinatorial Logic (Always Active) ##

    -- Opcode to Control Unit
    -- The Opcode is the 4 *upper* bits of the Instruction Register
    s_opcode <= s_ir(7 downto 4);
    
    -- ALU Logic (Generates output and flags)
    ALU_PROC: process(s_reg_a, s_reg_b, s_SUB)
        -- Use 9-bit intermediates to easily capture carry/borrow
        variable res_add : unsigned(8 downto 0);
        variable res_sub : unsigned(8 downto 0);
    begin
        -- Perform both calculations
        res_add := unsigned('0' & s_reg_a) + unsigned('0' & s_reg_b);
        res_sub := unsigned('0' & s_reg_a) - unsigned('0' & s_reg_b);

        -- Select the result based on the SUB signal
        if s_SUB = '1' then
            s_alu_out <= std_logic_vector(res_sub(7 downto 0));
            s_carry_flag <= res_sub(8); -- '1' indicates a borrow
            if res_sub(7 downto 0) = 0 then
                s_zero_flag <= '1';
            else
                s_zero_flag <= '0';
            end if;
        else
            s_alu_out <= std_logic_vector(res_add(7 downto 0));
            s_carry_flag <= res_add(8); -- '1' indicates a carry
            if res_add(7 downto 0) = 0 then
                s_zero_flag <= '1';
            else
                s_zero_flag <= '0';
            end if;
        end if;
    end process ALU_PROC;

end architecture sim;
```

***Kalo bener harusnya hasilnya Begini :*** 
![image](https://hackmd.io/_uploads/rJUqY4zgbx.png)

#### Hasil dijalankan : 
![image](https://hackmd.io/_uploads/H1VuYO_eZg.png)


### A. Jelaskan apa yang testbench tersebut lakukan dengan memakai control unit anda. Berikan cuplikan kodenya bagian mana yang melakukannya (HINT : liat di RAM di testbench) (tidak usah referensi) (20 pts)

testbench mengeksekusi operasi aritmatika (10 + 5) - 3menggunakan register A dan B.

isi memori:
![image](https://hackmd.io/_uploads/ryYGetue-x.png)

- instruksi yang dijalankan (s_ram):
1. hex 18 = 0001 1000
= LDA 8
load register A dengan isi dari memori 8 (10)
2. hex 59 = 0101 1001
= LDB 9
load register B dengan isi dari memori 9 (5)
3.  hex 30 = 0011 0000
= ADD
A + B, hasilnya disimpan di register A
4. hex 5A = 0101 1010
= LDB 10
load register B dengan isi dari memori 10 (3)
5. hex c0 = 1100 0000
= SUB
A - B, hasilnya disimpan di register A

# BoNUS (0 poin)

### 1. Modul PSD siapa yang paling sulit (sebutkan aslabnya)
semuanya (selalu gosong di cs)
### 2. Apakah anda senang belajar PSD selama ini
nope. PSD? more like PtSD 💀
### 3. Siapkah anda belajar assembly (teaser)
alamak