# 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 :***

#### Hasil dijalankan :

### 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:

- 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