home | terminal | snapshot | hardware | microcode engine | operating system | c compiler & assembler | c library | resources | photos & videos | system overview | interrupts & dma | instruction set | system verilog model | kernel overview | file system | system calls | shell | programs & games | how to build a program | github | youtube | contact

cpu_top.sv:

module cpu_top(
  input logic arst,
  input logic clk,
  //input logic [7:0] data_bus,
  input logic [7:0] pins_irq_req,
  input logic dma_req,
  input logic pin_wait,
  input logic ext_input,
  
  inout logic [7:0] data_bus,
  output logic [21:0] address_bus,
  //output logic [7:0] data_bus_out,
  output logic rd,
  output logic wr,
  output logic mem_io,
  output logic halt,
  output logic dma_ack
);
  import pa_cpu::*; 

// General registers
  logic [7:0] ah, al;
  logic [7:0] bh, bl;
  logic [7:0] ch, cl;
  logic [7:0] dh, dl;
  logic [7:0] gh, gl;
  
// System registers
  logic [7:0] ir;
  logic [7:0] pch, pcl;
  logic [7:0] ptb;
  logic [7:0] cpu_status;
  logic [7:0] cpu_flags;
  logic [7:0] irq_masks;
  logic [7:0] irq_status;
  logic [7:0] irq_vector;
  logic [7:0] irq_clear;

  logic status_dma_ack;
  logic status_irq_en;
  logic status_mode;
  logic status_paging_en;
  logic status_halt;
  logic status_displayreg_load;
  logic status_dir;

// Special registers
  logic [7:0] sph, spl;
  logic [7:0] ssph, sspl;
  logic [7:0] bph, bpl;
  logic [7:0] sih, sil;
  logic [7:0] dih, dil;
  logic [7:0] marh, marl;
  logic [7:0] mdrh, mdrl;
  logic [7:0] tdrh, tdrl;
  
// Buses
  logic [7:0] x_bus;
  logic [7:0] w_bus;
  logic [7:0] y_bus; 
  logic [7:0] k_bus;
  logic [7:0] z_bus; 

// ALU
  logic [7:0] alu_out;
  logic alu_zf;
  logic alu_cf_out;
  logic alu_sf;
  logic alu_of;
  logic alu_final_cf;
  logic [7:0] u_flags;
  logic alu_cf_in;
  logic irq_request;
// IRQ requests after passing through their corresponding DFFs
  logic [7:0] irq_dff;
  
// Control word fields
  logic [1:0] ctrl_typ;
  logic [6:0] ctrl_offset;
  logic ctrl_cond_invert;
  logic ctrl_cond_flag_src;
  logic [3:0] ctrl_cond_sel;
  logic ctrl_escape;
  logic [1:0] ctrl_u_zf_in_src;
  logic [1:0] ctrl_u_cf_in_src;
  logic ctrl_u_sf_in_src;
  logic ctrl_u_of_in_src;
  logic ctrl_ir_wrt;
  logic ctrl_status_wrt;
  logic [2:0] ctrl_shift_src;
  logic [1:0] ctrl_zbus_src;
  logic [5:0] ctrl_alu_a_src;
  logic [3:0] ctrl_alu_op;
  logic ctrl_alu_mode;
  logic [1:0] ctrl_alu_cf_in_src;
  logic ctrl_alu_cf_in_invert;
  logic ctrl_alu_cf_out_invert;
  logic [1:0] ctrl_zf_in_src;
  logic [2:0] ctrl_cf_in_src;
  logic [1:0] ctrl_sf_in_src;
  logic [2:0] ctrl_of_in_src;
  logic ctrl_rd;
  logic ctrl_wr;
  logic [2:0] ctrl_alu_b_src;
  logic ctrl_display_reg_load; // used during fetch to select and load register display
  logic ctrl_dl_wrt;
  logic ctrl_dh_wrt;
  logic ctrl_cl_wrt;
  logic ctrl_ch_wrt;
  logic ctrl_bl_wrt;
  logic ctrl_bh_wrt;
  logic ctrl_al_wrt;
  logic ctrl_ah_wrt;
  logic ctrl_mdr_in_src;
  logic ctrl_mdr_out_src;
  logic ctrl_mdr_out_en;
  logic ctrl_mdr_l_wrt;			
  logic ctrl_mdr_h_wrt;
  logic ctrl_tdr_l_wrt;
  logic ctrl_tdr_h_wrt;
  logic ctrl_di_l_wrt;
  logic ctrl_di_h_wrt;
  logic ctrl_si_l_wrt;
  logic ctrl_si_h_wrt;
  logic ctrl_mar_l_wrt;
  logic ctrl_mar_h_wrt;
  logic ctrl_bp_l_wrt;
  logic ctrl_bp_h_wrt;
  logic ctrl_pc_l_wrt;
  logic ctrl_pc_h_wrt;
  logic ctrl_sp_l_wrt;
  logic ctrl_sp_h_wrt;
  logic ctrl_gl_wrt;
  logic ctrl_gh_wrt;
  logic ctrl_int_vector_wrt;
  logic ctrl_irq_masks_wrt;		// wrt signals are also active low
  logic ctrl_mar_in_src;
  logic ctrl_int_ack;		      // active high
  logic ctrl_clear_all_ints;
  logic ctrl_ptb_wrt;
  logic ctrl_page_table_we; 
  logic ctrl_mdr_to_pagetable_data_en;
  logic ctrl_force_user_ptb;   // goes to board as page_table_addr_source via or gate
  logic [7:0] ctrl_immy;

// Derived signals
  logic pagetable_addr_source;
  logic bus_tristate;
  logic int_pending;

// Nets
  wire logic [15:0] mdr_to_pagetable_data;
  wire logic bus_rd;
  wire logic bus_wr;
  wire logic bus_mem_io;

  assign rd = ~bus_rd;
  assign wr = ~bus_wr;
  assign mem_io = bus_mem_io;
  assign halt = status_halt;
  assign dma_ack = status_dma_ack;

  assign status_dma_ack         = cpu_status[bitpos_cpu_status_dma_ack];
  assign status_irq_en          = cpu_status[bitpos_cpu_status_irq_en];
  assign status_mode            = cpu_status[bitpos_cpu_status_mode];
  assign status_paging_en       = cpu_status[bitpos_cpu_status_paging_en];
  assign status_halt            = cpu_status[bitpos_cpu_status_halt];
  assign status_displayreg_load = cpu_status[bitpos_cpu_status_displayreg_load];
  assign status_dir             = cpu_status[bitpos_cpu_status_dir];

/*************************
 Start of RTL code
**************************/

// ALU
  always_comb begin
    logic cf_muxed;
    case(ctrl_alu_cf_in_src)
      2'b00: cf_muxed = 1'b1;
      2'b01: cf_muxed = cpu_flags[1];
      2'b10: cf_muxed = u_flags[1];
      2'b11: cf_muxed = 1'b0;
    endcase
    alu_cf_in = cf_muxed ^ ctrl_alu_cf_in_invert;
  end
  alu u_alu(
    .a(x_bus),
    .b(y_bus),
    .cf_in(alu_cf_in),
    .op(ctrl_alu_op),
    .mode(ctrl_alu_mode),
    .alu_out(alu_out),
    .alu_cf_out(alu_cf_out)
  );
  assign alu_zf = ~|alu_out;
  assign alu_final_cf = ctrl_alu_cf_out_invert ^ alu_cf_out;
  assign alu_sf = z_bus[7];
  assign alu_of = (z_bus[7] ^ x_bus[7]) & ~((x_bus[7] ^ y_bus[7]) ^ ~(ctrl_alu_op[0] & ctrl_alu_op[3] & ~(ctrl_alu_op[2] | ctrl_alu_op[1])));
  
// CPU Flags
  always_ff @(posedge clk) begin
    case(ctrl_zf_in_src)
      2'b00: cpu_flags[bitpos_cpu_flags_zf] <= cpu_flags[bitpos_cpu_flags_zf];
      2'b01: cpu_flags[bitpos_cpu_flags_zf] <= alu_zf;
      2'b10: cpu_flags[bitpos_cpu_flags_zf] <= cpu_flags[bitpos_cpu_flags_zf] & alu_zf;
      2'b11: cpu_flags[bitpos_cpu_flags_zf] <= z_bus[0];
    endcase
    case(ctrl_cf_in_src)
      3'b000: cpu_flags[bitpos_cpu_flags_cf] <= cpu_flags[bitpos_cpu_flags_cf];
      3'b001: cpu_flags[bitpos_cpu_flags_cf] <= alu_final_cf;
      3'b010: cpu_flags[bitpos_cpu_flags_cf] <= alu_out[0];
      3'b011: cpu_flags[bitpos_cpu_flags_cf] <= z_bus[1];
      3'b100: cpu_flags[bitpos_cpu_flags_cf] <= alu_out[7];
      default: cpu_flags[bitpos_cpu_flags_cf] <= cpu_flags[bitpos_cpu_flags_cf];
    endcase
    case(ctrl_sf_in_src)
      2'b00: cpu_flags[bitpos_cpu_flags_sf] <= cpu_flags[bitpos_cpu_flags_sf];
      2'b01: cpu_flags[bitpos_cpu_flags_sf] <= z_bus[7];
      2'b10: cpu_flags[bitpos_cpu_flags_sf] <= 1'b0;
      2'b11: cpu_flags[bitpos_cpu_flags_sf] <= z_bus[2];
    endcase
    case(ctrl_of_in_src)
      3'b000: cpu_flags[bitpos_cpu_flags_of] <= cpu_flags[bitpos_cpu_flags_of];
      3'b001: cpu_flags[bitpos_cpu_flags_of] <= alu_of;
      3'b010: cpu_flags[bitpos_cpu_flags_of] <= z_bus[7];
      3'b011: cpu_flags[bitpos_cpu_flags_of] <= z_bus[3];
      3'b100: cpu_flags[bitpos_cpu_flags_of] <= u_flags[bitpos_cpu_flags_sf] ^ z_bus[7];
      default: cpu_flags[bitpos_cpu_flags_of] <= cpu_flags[bitpos_cpu_flags_of];
    endcase
  end

// z_bus assignments
  always_comb begin
    logic extremity_bit;
    case(ctrl_shift_src)
      3'b000: extremity_bit = 1'b0;
      3'b001: extremity_bit = u_flags[1]; // u_cf
      3'b010: extremity_bit = cpu_flags[1]; // msw cf
      3'b011: extremity_bit = alu_out[0];
      3'b100: extremity_bit = alu_out[7];
      3'b101: extremity_bit = 1'b1;
      3'b110: extremity_bit = 1'b1;
      3'b111: extremity_bit = 1'b1;
    endcase
    case(ctrl_zbus_src)
      2'b00: z_bus = alu_out;
      2'b01: z_bus = (alu_out >> 1) | {extremity_bit, 7'b000_0000};
      2'b10: z_bus = (alu_out << 1) | {7'b000_0000, extremity_bit};
      2'b11: z_bus = {8{alu_out[7]}};
    endcase
  end

// w_bus assignment
  always_comb begin
    case(ctrl_alu_a_src[4:0])
      5'b00000: w_bus = al;
      5'b00001: w_bus = ah;
      5'b00010: w_bus = bl;
      5'b00011: w_bus = bh;
      5'b00100: w_bus = cl;
      5'b00101: w_bus = ch;
      5'b00110: w_bus = dl;
      5'b00111: w_bus = dh;
      5'b01000: w_bus = spl;
      5'b01001: w_bus = sph;
      5'b01010: w_bus = bpl;
      5'b01011: w_bus = bph;
      5'b01100: w_bus = sil;
      5'b01101: w_bus = sih;
      5'b01110: w_bus = dil;
      5'b01111: w_bus = dih;
      5'b10000: w_bus = pcl;
      5'b10001: w_bus = pch;
      5'b10010: w_bus = marl;
      5'b10011: w_bus = marh;
      5'b10100: w_bus = mdrl;
      5'b10101: w_bus = mdrh;
      5'b10110: w_bus = tdrl;
      5'b10111: w_bus = tdrh;
      5'b11000: w_bus = sspl;
      5'b11001: w_bus = ssph;
      5'b11010: w_bus = irq_vector;
      5'b11011: w_bus = irq_masks;
      5'b11100: w_bus = irq_status;
      5'b11101: w_bus = '0;
      5'b11110: w_bus = '0;
      5'b11111: w_bus = '0;
    endcase
  end     

// x_bus assignment
  always_comb begin
    if(ctrl_alu_a_src[5] == 1'b0) begin
      x_bus = w_bus;
    end
    else begin
      case(ctrl_alu_a_src[1:0])
        2'b00: x_bus = cpu_flags;
        2'b01: x_bus = cpu_status;
        2'b10: x_bus = gl;
        2'b11: x_bus = gh;
      endcase
    end
  end
  
// k_bus assignment
  always_comb begin
    case(ctrl_alu_b_src[1:0])
      2'b00: k_bus = mdrl;
      2'b01: k_bus = mdrh;
      2'b10: k_bus = tdrl;
      2'b11: k_bus = tdrh;
    endcase
  end

// y_bus assignment
  always_comb begin
    if(ctrl_alu_b_src[2] == 1'b0) begin
      y_bus = ctrl_immy;
    end
    else begin
      y_bus = k_bus;
    end
  end

// z_bus to Registers Block
  always_ff @(posedge clk) begin
    if(ctrl_al_wrt == 1'b0) al <= z_bus;
    if(ctrl_ah_wrt == 1'b0) ah <= z_bus;
    if(ctrl_bl_wrt == 1'b0) bl <= z_bus;
    if(ctrl_bh_wrt == 1'b0) bh <= z_bus;
    if(ctrl_cl_wrt == 1'b0) cl <= z_bus;
    if(ctrl_ch_wrt == 1'b0) ch <= z_bus;
    if(ctrl_dl_wrt == 1'b0) dl <= z_bus;
    if(ctrl_dh_wrt == 1'b0) dh <= z_bus;
    if(ctrl_gl_wrt == 1'b0) gl <= z_bus;
    if(ctrl_gh_wrt == 1'b0) gh <= z_bus;

    if(ctrl_tdr_l_wrt == 1'b0) tdrl <= z_bus;
    if(ctrl_tdr_h_wrt == 1'b0) tdrh <= z_bus;
    if(ctrl_di_l_wrt == 1'b0) dil <= z_bus;
    if(ctrl_di_h_wrt == 1'b0) dih <= z_bus;
    if(ctrl_si_l_wrt == 1'b0) sil <= z_bus;
    if(ctrl_si_h_wrt == 1'b0) sih <= z_bus;
    if(ctrl_bp_l_wrt == 1'b0) bpl <= z_bus;
    if(ctrl_bp_h_wrt == 1'b0) bph <= z_bus;
    if(ctrl_sp_l_wrt == 1'b0) spl <= z_bus;
    if(ctrl_sp_h_wrt == 1'b0) sph <= z_bus;
    if(ctrl_pc_l_wrt == 1'b0) pcl <= z_bus;
    if(ctrl_pc_h_wrt == 1'b0) pch <= z_bus;
    if(ctrl_status_wrt == 1'b0) cpu_status <= z_bus;
    if(ctrl_irq_masks_wrt == 1'b0) irq_masks <= z_bus;
    if(ctrl_sp_l_wrt == 1'b0 && status_mode == 1'b0) sspl <= z_bus;
    if(ctrl_sp_h_wrt == 1'b0 && status_mode == 1'b0) ssph <= z_bus;

    if(ctrl_ir_wrt == 1'b0) ir <= data_bus;
    if(ctrl_mar_l_wrt == 1'b0) marl <= ctrl_mar_in_src ? pcl : z_bus;
    if(ctrl_mar_h_wrt == 1'b0) marh <= ctrl_mar_in_src ? pch : z_bus;
    if(ctrl_mdr_l_wrt == 1'b0) mdrl <= ctrl_mdr_in_src ? data_bus : z_bus;
    if(ctrl_mdr_h_wrt == 1'b0) mdrh <= ctrl_mdr_in_src ? data_bus : z_bus;

    if(ctrl_ptb_wrt == 1'b0) ptb <= z_bus;
  end

// Page Table
  assign pagetable_addr_source = ctrl_force_user_ptb || status_mode;
  assign mdr_to_pagetable_data = ctrl_mdr_to_pagetable_data_en ? {mdrh, mdrl} : 'z;
  memory #(PAGETABLE_RAM_SIZE) u_pagetable_low(
    .ce_n(1'b0),
    .oe_n(ctrl_mdr_to_pagetable_data_en),
    .we_n(~ctrl_page_table_we),
    .address({pagetable_addr_source ? ptb : 8'h00, marh[7:3]}),
    .data_in(mdr_to_pagetable_data[7:0]),
    .data_out(mdr_to_pagetable_data[7:0])    
  );
  memory #(PAGETABLE_RAM_SIZE) u_pagetable_high(
    .ce_n(1'b0),
    .oe_n(ctrl_mdr_to_pagetable_data_en),
    .we_n(~ctrl_page_table_we),
    .address({pagetable_addr_source ? ptb : 8'h00, marh[7:3]}),
    .data_in(mdr_to_pagetable_data[15:8]),
    .data_out(mdr_to_pagetable_data[15:8])    
  );
  assign bus_tristate = status_dma_ack || status_halt;
  assign address_bus = bus_tristate ? 'z : status_paging_en ? {mdr_to_pagetable_data[10:0], marh[2:0], marl[7:0]} : {6'b000000, marh, marl};
  assign bus_mem_io = bus_tristate ? 1'bz : status_paging_en ? mdr_to_pagetable_data[11] : 1'b1;
  assign bus_rd = bus_tristate ? 1'bz : ctrl_rd;
  assign bus_wr = bus_tristate ? 1'bz : ctrl_wr;
  assign data_bus = ctrl_mdr_out_en ? ctrl_mdr_out_src ? mdrh : mdrl : 'z;

// Interrupts
  for(genvar i = 0; i < 8; i++) begin
    assign irq_clear[i] = ctrl_int_ack && irq_vector[3:1] == i;
    always_ff @(posedge pins_irq_req[i], posedge ctrl_clear_all_ints, posedge irq_clear[i]) begin
      if(ctrl_clear_all_ints == 1'b1 || irq_clear[i] == 1'b1) irq_dff[i] <= 1'b0;
      else irq_dff[i] <= 1'b1;
    end
  end
  always_ff @(posedge clk) begin
    irq_status <= irq_dff;
  end
  // IRQ Handling Block
  always_ff @(posedge clk) begin
    logic [7:0] irqs_masked;
    logic [2:0] irq_encoded;

    irqs_masked = irq_status & irq_masks;
    irq_request = |irqs_masked; // Check if any IRQ is requested
    if(irqs_masked[0] == 1'b1) irq_encoded = 000;
    else if(irqs_masked[1] == 1'b1) irq_encoded = 3'b001;
    else if(irqs_masked[2] == 1'b1) irq_encoded = 3'b010;
    else if(irqs_masked[3] == 1'b1) irq_encoded = 3'b011;
    else if(irqs_masked[4] == 1'b1) irq_encoded = 3'b100;
    else if(irqs_masked[5] == 1'b1) irq_encoded = 3'b101;
    else if(irqs_masked[6] == 1'b1) irq_encoded = 3'b110;
    else if(irqs_masked[7] == 1'b1) irq_encoded = 3'b111;
    
    if(ctrl_int_vector_wrt == 1'b0) begin
      irq_vector <= {4'b0000, irq_encoded[2:0], 1'b0};
    end
  end
  assign int_pending = irq_request & status_irq_en;

// Microcode Sequencer
  microcode_sequencer u_microcode_sequencer(
    .arst(arst),
    .clk(clk),
    .ir(ir),
    .cpu_flags(cpu_flags),
    .cpu_status(cpu_status),
    .z_bus(z_bus),
    .alu_out(alu_out),
    .alu_zf(alu_zf),
    .alu_of(alu_of),
    .alu_final_cf(alu_final_cf),
    .dma_req(dma_req),
    ._wait(pin_wait),
    .int_pending(int_pending),
    .ext_input(ext_input),
    .u_flags(u_flags),

    .* // control word
  );


endmodule



sol1_top.sv:
module sol1_top;
  import pa_testbench::*;

	logic arst;
	logic stop_clk_req;
  logic clk;
	logic halt;
	logic dma_req;
	logic dma_ack;
	logic [7:0] pins_irq_req;
  logic pin_wait;
  logic ext_input;

// Bus
	wire logic [21:0] address_bus;
	wire logic [7:0] data_bus;
	wire logic rd;
	wire logic wr;
	wire logic mem_io;

// Chip selects
  logic bios_ram_cs;
  logic bios_rom_cs;
  logic uart0_cs;
  logic uart1_cs;
  logic rtc_cs;
  logic pio0_cs;
  logic pio1_cs;
  logic ide_cs;
  logic timer_cs;
  logic bios_config_cs;

  // Address decoding support wires
  wire logic inside_real_mode_addr_space;
  wire logic addr_bus_7_to_14_alltrue;
  wire logic peripheral_access;

  initial begin
    // Load bios code into rom
    static int fp = $fopen("../software/obj/bios.obj", "rb");
    if(!fp) $fatal("Failed to open bios.obj");
    if(!$fread(sol1_top.u_bios_rom.mem, fp)) $fatal("Failed to read bios.obj");
    $display("OK.");

    // Start CPU...
		pins_irq_req = 8'h00;
		dma_req = 1'b0;
    ext_input = 1'b0;
    pin_wait = 1'b0;

    arst = 1'b1;
		stop_clk_req = 1'b1;
    #100ns;
		arst = 1'b0;	
    #100ns;
		stop_clk_req = 1'b0;

		#100ms $stop;
  end

	clock u_clock(
		.arst(arst),
		.stop_clk_req(stop_clk_req),
		.clk_out(clk)
	);

	cpu_top u_cpu_top(
		.arst(arst),
		.clk(clk),
		.pins_irq_req(pins_irq_req),
		.dma_req(dma_req),
		.address_bus(address_bus),
		//.data_bus_in(data_bus),
		//.data_bus_out(data_bus),
		.data_bus(data_bus),
		.rd(rd),
		.wr(wr),
		.mem_io(mem_io),
		.halt(halt),
		.dma_ack(dma_ack),
    .pin_wait(pin_wait),
    .ext_input(ext_input)
	);

  memory #(32 * KB) u_bios_rom(
    .ce_n(bios_rom_cs),
    .oe_n(rd),
    .we_n(1'b1),
    .address(address_bus[14:0]),
    .data_in(data_bus),
    .data_out(data_bus)
  );
  memory #(32 * KB) u_bios_ram(
    .ce_n(bios_ram_cs),
    .oe_n(rd),
    .we_n(wr),
    .address(address_bus[14:0]),
    .data_in(data_bus),
    .data_out(data_bus)
  );

  ide u_ide(
    .arst(arst),
    .clk(clk),
    .ce_n(ide_cs),
    .oe_n(rd),
    .we_n(wr),
    .address(address_bus[2:0]),
    .data_in(data_bus),
    .data_out(data_bus)
  );

  uart u_uart0(
    .arst(arst),
    .clk(clk),
    .ce_n(uart0_cs),
    .oe_n(rd),
    .we_n(wr),
    .address(address_bus[2:0]),
    .data_in(data_bus),
    .data_out(data_bus)
  );

  // Declare 8x 512KB RAM modules
  generate for(genvar i = 0; i < 8; i++) begin
    memory #(512 * KB) u_ram(
      .ce_n(!(address_bus[21:19] == i[2:0] && !mem_io)),
      .oe_n(rd),
      .we_n(wr),
      .address(address_bus[18:0]),
      .data_in(data_bus),
      .data_out(data_bus)
    );
  end endgenerate

  assign addr_bus_7_to_14_alltrue = & address_bus[14:7];
  assign inside_real_mode_addr_space = ~| address_bus[21:16];
  assign peripheral_access = addr_bus_7_to_14_alltrue && address_bus[15] && mem_io;

  assign bios_rom_cs    = !(mem_io && inside_real_mode_addr_space && !address_bus[15]);
  assign bios_ram_cs    = !(mem_io && inside_real_mode_addr_space && !addr_bus_7_to_14_alltrue && address_bus[15]);
  assign uart0_cs       = peripheral_access ? !(address_bus[6:4] == 3'b000) : 1'b1;
  assign uart1_cs       = peripheral_access ? !(address_bus[6:4] == 3'b001) : 1'b1;
  assign rtc_cs         = peripheral_access ? !(address_bus[6:4] == 3'b010) : 1'b1;
  assign pio0_cs        = peripheral_access ? !(address_bus[6:4] == 3'b011) : 1'b1;
  assign pio1_cs        = peripheral_access ? !(address_bus[6:4] == 3'b100) : 1'b1;
  assign ide_cs         = peripheral_access ? !(address_bus[6:4] == 3'b101) : 1'b1;
  assign timer_cs       = peripheral_access ? !(address_bus[6:4] == 3'b110) : 1'b1;
  assign bios_config_cs = peripheral_access ? !(address_bus[6:4] == 3'b111) : 1'b1;

endmodule



microcode_sequencer.sv:
module microcode_sequencer(
  input logic arst,
  input logic clk,
  input logic [7:0] ir,
  input logic [7:0] cpu_flags,
  input logic [7:0] cpu_status,
  input logic [7:0] z_bus,
  input logic [7:0] alu_out,
  input logic alu_zf,
  input logic alu_of,
  input logic alu_final_cf,
  input logic dma_req,
  input logic _wait,
  input logic int_pending,
  input logic ext_input,
  
  output logic [7:0] u_flags,
  
  output logic [1:0] ctrl_typ,
  output logic [6:0] ctrl_offset,
  output logic ctrl_cond_invert,
  output logic ctrl_cond_flag_src,
  output logic [3:0] ctrl_cond_sel,
  output logic ctrl_escape,
  output logic [1:0] ctrl_u_zf_in_src,
  output logic [1:0] ctrl_u_cf_in_src,
  output logic ctrl_u_sf_in_src,
  output logic ctrl_u_of_in_src,
  output logic ctrl_ir_wrt,
  output logic ctrl_status_wrt,
  output logic [2:0] ctrl_shift_src,
  output logic [1:0] ctrl_zbus_src,
  output logic [5:0] ctrl_alu_a_src,
  output logic [3:0] ctrl_alu_op,
  output logic ctrl_alu_mode,
  output logic [1:0] ctrl_alu_cf_in_src,
  output logic ctrl_alu_cf_in_invert,
  output logic ctrl_alu_cf_out_invert,
  output logic [1:0] ctrl_zf_in_src,
  output logic [2:0] ctrl_cf_in_src,
  output logic [1:0] ctrl_sf_in_src,
  output logic [2:0] ctrl_of_in_src,
  output logic ctrl_rd,
  output logic ctrl_wr,
  output logic [2:0] ctrl_alu_b_src,
  output logic ctrl_display_reg_load, // used during fetch to select and load register display
  output logic ctrl_dl_wrt,
  output logic ctrl_dh_wrt,
  output logic ctrl_cl_wrt,
  output logic ctrl_ch_wrt,
  output logic ctrl_bl_wrt,
  output logic ctrl_bh_wrt,
  output logic ctrl_al_wrt,
  output logic ctrl_ah_wrt,
  output logic ctrl_mdr_in_src,
  output logic ctrl_mdr_out_src,
  output logic ctrl_mdr_out_en,
  output logic ctrl_mdr_l_wrt,			
  output logic ctrl_mdr_h_wrt,
  output logic ctrl_tdr_l_wrt,
  output logic ctrl_tdr_h_wrt,
  output logic ctrl_di_l_wrt,
  output logic ctrl_di_h_wrt,
  output logic ctrl_si_l_wrt,
  output logic ctrl_si_h_wrt,
  output logic ctrl_mar_l_wrt,
  output logic ctrl_mar_h_wrt,
  output logic ctrl_bp_l_wrt,
  output logic ctrl_bp_h_wrt,
  output logic ctrl_pc_l_wrt,
  output logic ctrl_pc_h_wrt,
  output logic ctrl_sp_l_wrt,
  output logic ctrl_sp_h_wrt,
  output logic ctrl_gl_wrt,
  output logic ctrl_gh_wrt,
  output logic ctrl_int_vector_wrt,
  output logic ctrl_irq_masks_wrt,		// wrt signals are also active low
  output logic ctrl_mar_in_src,
  output logic ctrl_int_ack,		      // active high
  output logic ctrl_clear_all_ints,
  output logic ctrl_ptb_wrt,
  output logic ctrl_page_table_we, 
  output logic ctrl_mdr_to_pagetable_data_en,
  output logic ctrl_force_user_ptb,   // goes to board as page_table_addr_source via or gate
  output logic [7:0] ctrl_immy
);
  import pa_microcode::*;
  import pa_cpu::*;

  logic status_dma_ack;
  logic status_irq_en;
  logic status_mode;
  logic status_paging_en;
  logic status_halt;
  logic status_displayreg_load;
  logic status_dir;

  logic any_interruption;
  logic [CONTROL_WORD_WIDTH - 1 : 0] ucode_roms [CYCLES_PER_INSTRUCTION * NBR_INSTRUCTIONS];
  logic [CONTROL_WORD_WIDTH - 1 : 0] control_word;
  logic [CONTROL_WORD_WIDTH - 1 : 0] control_word_n;
  logic [13:0] u_address;
  logic final_condition;

  assign status_dma_ack         = cpu_status[bitpos_cpu_status_dma_ack];
  assign status_irq_en          = cpu_status[bitpos_cpu_status_irq_en];
  assign status_mode            = cpu_status[bitpos_cpu_status_mode];
  assign status_paging_en       = cpu_status[bitpos_cpu_status_paging_en];
  assign status_halt            = cpu_status[bitpos_cpu_status_halt];
  assign status_displayreg_load = cpu_status[bitpos_cpu_status_displayreg_load];
  assign status_dir             = cpu_status[bitpos_cpu_status_dir];

  assign control_word = ucode_roms[u_address];

  always_ff @(negedge clk) begin
    control_word_n <= control_word;
  end

  assign any_interruption = dma_req | int_pending;

  assign ctrl_typ = control_word[bitpos_typ1 : bitpos_typ0];
  assign ctrl_offset = control_word[bitpos_offset_6 : bitpos_offset_0];
  assign ctrl_cond_invert = control_word[bitpos_cond_invert];
  assign ctrl_cond_flag_src = control_word[bitpos_cond_flag_src];
  assign ctrl_cond_sel = control_word[bitpos_cond_sel_3 : bitpos_cond_sel_0];
  assign ctrl_escape = control_word[bitpos_escape];

  assign ctrl_u_zf_in_src = control_word_n[bitpos_u_zf_in_src_1 : bitpos_u_zf_in_src_0];
  assign ctrl_u_cf_in_src = control_word_n[bitpos_u_cf_in_src_1 : bitpos_u_cf_in_src_0];
  assign ctrl_u_sf_in_src = control_word_n[bitpos_u_sf_in_src];
  assign ctrl_u_of_in_src = control_word_n[bitpos_u_of_in_src];
  assign ctrl_ir_wrt = control_word_n[bitpos_ir_wrt];
  assign ctrl_status_wrt = control_word_n[bitpos_status_wrt];
  assign ctrl_shift_src = control_word_n[bitpos_shift_src_2 : bitpos_shift_src_0];
  assign ctrl_zbus_src = control_word_n[bitpos_zbus_src_1 : bitpos_zbus_src_0];
  assign ctrl_alu_a_src = control_word_n[bitpos_alu_a_src_5 : bitpos_alu_a_src_0];
  assign ctrl_alu_op = control_word_n[bitpos_alu_op_3 : bitpos_alu_op_0];
  assign ctrl_alu_mode = control_word_n[bitpos_alu_mode];
  assign ctrl_alu_cf_in_src = control_word_n[bitpos_alu_cf_in_src_1 : bitpos_alu_cf_in_src_0];
  assign ctrl_alu_cf_in_invert = control_word_n[bitpos_alu_cf_in_invert];
  assign ctrl_alu_cf_out_invert = control_word_n[bitpos_alu_cf_out_invert];
  assign ctrl_zf_in_src = control_word_n[bitpos_zf_in_src_1 : bitpos_zf_in_src_0];
  assign ctrl_cf_in_src = control_word_n[bitpos_cf_in_src_2 : bitpos_cf_in_src_0];
  assign ctrl_sf_in_src = control_word_n[bitpos_sf_in_src_1 : bitpos_sf_in_src_0];
  assign ctrl_of_in_src = control_word_n[bitpos_of_in_src_2 : bitpos_of_in_src_0];
  assign ctrl_rd = control_word_n[bitpos_rd];
  assign ctrl_wr = control_word_n[bitpos_wr];
  assign ctrl_alu_b_src = control_word_n[bitpos_alu_b_src_2 : bitpos_alu_b_src_0];
  assign ctrl_display_reg_load = control_word_n[bitpos_display_reg_load]; // used during fetch to select and load register display
  assign ctrl_dl_wrt = control_word_n[bitpos_dl_wrt];
  assign ctrl_dh_wrt = control_word_n[bitpos_dh_wrt];
  assign ctrl_cl_wrt = control_word_n[bitpos_cl_wrt];
  assign ctrl_ch_wrt = control_word_n[bitpos_ch_wrt];
  assign ctrl_bl_wrt = control_word_n[bitpos_bl_wrt];
  assign ctrl_bh_wrt = control_word_n[bitpos_bh_wrt];
  assign ctrl_al_wrt = control_word_n[bitpos_al_wrt];
  assign ctrl_ah_wrt = control_word_n[bitpos_ah_wrt];
  assign ctrl_mdr_in_src = control_word_n[bitpos_mdr_in_src];
  assign ctrl_mdr_out_src = control_word_n[bitpos_mdr_out_src];
  assign ctrl_mdr_out_en = control_word_n[bitpos_mdr_out_en];
  assign ctrl_mdr_l_wrt = control_word_n[bitpos_mdr_l_wrt];			
  assign ctrl_mdr_h_wrt = control_word_n[bitpos_mdr_h_wrt];
  assign ctrl_tdr_l_wrt = control_word_n[bitpos_tdr_l_wrt];
  assign ctrl_tdr_h_wrt = control_word_n[bitpos_tdr_h_wrt];
  assign ctrl_di_l_wrt = control_word_n[bitpos_di_l_wrt];
  assign ctrl_di_h_wrt = control_word_n[bitpos_di_h_wrt];
  assign ctrl_si_l_wrt = control_word_n[bitpos_si_l_wrt];
  assign ctrl_si_h_wrt = control_word_n[bitpos_si_h_wrt];
  assign ctrl_mar_l_wrt = control_word_n[bitpos_mar_l_wrt];
  assign ctrl_mar_h_wrt = control_word_n[bitpos_mar_h_wrt];
  assign ctrl_bp_l_wrt = control_word_n[bitpos_bp_l_wrt];
  assign ctrl_bp_h_wrt = control_word_n[bitpos_bp_h_wrt];
  assign ctrl_pc_l_wrt = control_word_n[bitpos_pc_l_wrt];
  assign ctrl_pc_h_wrt = control_word_n[bitpos_pc_h_wrt];
  assign ctrl_sp_l_wrt = control_word_n[bitpos_sp_l_wrt];
  assign ctrl_sp_h_wrt = control_word_n[bitpos_sp_h_wrt];
  assign ctrl_gl_wrt = control_word_n[bitpos_gl_wrt];
  assign ctrl_gh_wrt = control_word_n[bitpos_gh_wrt];
  assign ctrl_int_vector_wrt = control_word_n[bitpos_int_vector_wrt];
  assign ctrl_irq_masks_wrt = control_word_n[bitpos_irq_masks_wrt];		// wrt signals are also active low
  assign ctrl_mar_in_src = control_word_n[bitpos_mar_in_src];
  assign ctrl_int_ack = control_word_n[bitpos_int_ack];		      // active high
  assign ctrl_clear_all_ints = control_word_n[bitpos_clear_all_ints];
  assign ctrl_ptb_wrt = control_word_n[bitpos_ptb_wrt];
  assign ctrl_page_table_we = control_word_n[bitpos_page_table_we]; 
  assign ctrl_mdr_to_pagetable_data_en = control_word_n[bitpos_mdr_to_pagetable_data_en];
  assign ctrl_force_user_ptb = control_word_n[bitpos_force_user_ptb];   // goes to board as page_table_addr_source via or gate
  assign ctrl_immy = control_word_n[bitpos_immy_7 : bitpos_immy_0];

  always_comb begin
    logic zf_muxed, cf_muxed, sf_muxed, of_muxed;
    logic condition;
    
    zf_muxed = ctrl_cond_flag_src ? u_flags[0] : cpu_flags[0];
    cf_muxed = ctrl_cond_flag_src ? u_flags[1] : cpu_flags[1];
    sf_muxed = ctrl_cond_flag_src ? u_flags[2] : cpu_flags[2];
    of_muxed = ctrl_cond_flag_src ? u_flags[3] : cpu_flags[3];

    case(ctrl_cond_sel)
      4'b0000: begin
        condition = zf_muxed;
      end
      4'b0001: begin
        condition = cf_muxed;
      end
      4'b0010: begin
        condition = sf_muxed;
      end
      4'b0011: begin
        condition = of_muxed;
      end
      4'b0100: begin
        condition = sf_muxed ^ of_muxed;
      end
      4'b0101: begin
        condition = (sf_muxed ^ of_muxed) | zf_muxed;
      end
      4'b0110: begin
        condition = cf_muxed | zf_muxed;
      end
      4'b0111: begin
        condition = dma_req;
      end
      4'b1000: begin
        condition = status_mode;
      end
      4'b1001: begin
        condition = _wait;
      end
      4'b1010: begin
        condition = int_pending;
      end
      4'b1011: begin
        condition = ext_input;
      end
      4'b1100: begin
        condition = status_dir;
      end
      4'b1101: begin
        condition = status_displayreg_load;
      end
      4'b1110: condition = 1'b0;
      4'b1111: condition = 1'b0;
    endcase

    final_condition = condition ^ ctrl_cond_invert;
  end

  // DFF for u_flags register
  always_ff @(posedge clk) begin
    // u_zf
    case(ctrl_u_zf_in_src)
      2'b00: u_flags[0] <= u_flags[0];
      2'b01: u_flags[0] <= alu_zf;
      2'b10: u_flags[0] <= u_flags[0] & alu_zf;
      2'b11: u_flags[0] <= u_flags[0];
    endcase
    // u_cf
    case(ctrl_u_cf_in_src)
      2'b00: u_flags[1] <= u_flags[1];
      2'b01: u_flags[1] <= alu_final_cf;
      2'b10: u_flags[1] <= alu_out[0];
      2'b11: u_flags[1] <= alu_out[7];
    endcase
    // u_sf
    case(ctrl_u_sf_in_src)
      1'b0: u_flags[2] <= u_flags[2];
      1'b1: u_flags[2] <= z_bus[7];
    endcase
    // u_of
    case(ctrl_u_of_in_src)
      1'b0: u_flags[3] <= u_flags[3];
      1'b1: u_flags[3] <= alu_of;
    endcase
  end

  always_ff @(posedge clk, posedge arst) begin
    if(arst) u_address <= '0;
    else case(ctrl_typ)
      2'b00:
        u_address <= u_address + ctrl_offset;
      2'b01:
        if(final_condition) u_address <= u_address + ctrl_offset;
        else u_address <= u_address + 14'b1;
      2'b10:
        if(any_interruption) u_address <= TRAP_U_ADDR;
        else u_address <= FETCH_U_ADDR;
      2'b11:
        u_address <= {ir, 1'b0, ctrl_escape, 4'b0000};
    endcase
  end

// Load microcode ROM files into microcode memory
  initial begin
    bit [7:0] rom [CYCLES_PER_INSTRUCTION * NBR_INSTRUCTIONS];
    static string rom_base = "../hardware/microcode/roms/rom";
    int file;
    string filename;

    for(int rom_number = 0; rom_number <= 14; rom_number++) begin
      filename = $sformatf("%s%0d", rom_base, rom_number);
      file = $fopen(filename, "rb");
      if(!file) $fatal("Failed to open file.");
      if(!$fread(rom, file)) $fatal("Failed to read file.");

      $display("Loading microcode ROM: ", filename);
      for(int i = 0; i < CYCLES_PER_INSTRUCTION * NBR_INSTRUCTIONS; i++) begin
        ucode_roms[i][rom_number * 8 +: 8] = rom[i][7:0];
      end
    end
  end



endmodule



ide.sv:
module ide(
  input logic arst,
  input logic clk,
  input logic ce_n,
  input logic oe_n,
  input logic we_n,
  input logic [2:0] address,
  input logic [7:0] data_in,

  output logic [7:0] data_out
);
  import pa_testbench::*;
  
  typedef enum logic [3:0] {
    RESET_ST = 4'h0,
    BUSY_ST,
    READ_START_ST,
    READ_ST,
    WRITE_START_ST,
    WRITE_ST,
    COMPLETE_ST
  } t_ideState;

  t_ideState currentState;
  t_ideState nextState;

  logic [7:0] LBA [2:0];
  logic [9:0] byteCounter;
  logic [7:0] mem [672 * KB];
  logic [7:0] registers [7:0];
  logic [7:0] command;
  logic [7:0] status;

  initial begin
    static int fp = $fopen("../disk_backups/image_10Mar2023", "rb");
    $display("Loading disk image...");
    if(!fp) $fatal("Failed to open disk image");
    if(!$fread(mem, fp)) $fatal("Failed to read disk image");
    $display("OK.");
  end

  assign data_out = !ce_n && !oe_n && we_n ? address == 3'h7 ? status : registers[address] : 'z;
  assign LBA = registers[5:3];

// State machine
  always @(posedge clk, posedge arst) begin
    if(arst) begin
      command <= '0;
      status <= 8'b0000_0000;
      byteCounter <= '0;
    end
    else case(currentState)
      RESET_ST: begin
      end
      WRITE_START_ST: begin
        byteCounter <= '0;
        status <= status | 8'b0000_1000; // not finished
      end
      READ_START_ST: begin
        byteCounter <= '0;
        status <= status | 8'b0000_1000; // not finished
      end
      COMPLETE_ST: begin
        status <= status & 8'b1111_0111; // finished
        command <= '0;
      end
    endcase
  end

  always @(negedge oe_n, negedge we_n) begin
    if(!oe_n && address == 3'h0 && !ce_n) begin
      registers[0] <= mem[{LBA[2], LBA[1], LBA[0]} + byteCounter];
      byteCounter <= byteCounter + 10'd1;
    end
    else if(!we_n && !ce_n) begin
      if(address == 3'h0) begin
        mem[{LBA[2], LBA[1], LBA[0]} + byteCounter] <= data_in;
        registers[0] <= data_in; // for completion sake
        byteCounter <= byteCounter + 10'd1;
      end
      else if(!we_n && !ce_n && address == 3'h7) command <= data_in;
      else registers[address] <= data_in;
    end
  end

  always_ff @(posedge clk, posedge arst) begin
    if(arst) begin
      currentState <= RESET_ST;
    end
    else currentState <= nextState;
  end

  always_comb begin
    nextState = currentState;
    case(currentState)
      RESET_ST:
        if(command == 8'h20) nextState = READ_START_ST;
        else if(command == 8'h30) nextState = WRITE_START_ST;
      WRITE_START_ST:
        nextState = WRITE_ST;
      READ_START_ST:
        nextState = READ_ST;
      READ_ST:
        if(byteCounter == 10'd512) nextState = COMPLETE_ST;
        else if(!oe_n && !ce_n && address == 3'h0) nextState = READ_ST;
      WRITE_ST:
        if(byteCounter == 10'd512) nextState = COMPLETE_ST;
        else if(!we_n && !ce_n && address == 3'h0) nextState = WRITE_ST;
      COMPLETE_ST:
        nextState = RESET_ST;
    endcase
  end

endmodule



alu.sv:
module alu(
  input logic [7:0] a,
  input logic [7:0] b,
  input logic cf_in,
  input logic [3:0] op,
  input logic mode,

  output logic [7:0] alu_out,
  output logic alu_cf_out
);
  logic temp_cf_out;

  always_comb begin
    case(op)
      4'b0000: begin
        {temp_cf_out, alu_out} = mode ? ~a : a + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b0001: begin
        {temp_cf_out, alu_out} = mode ? ~(a | b) : (a | b) + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b0010: begin
        {temp_cf_out, alu_out} = mode ? ~a & b : (a | ~b) + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b0011: begin
        {temp_cf_out, alu_out} = mode ? 8'h00 : 8'hFF + {7'b0, ~cf_in}; // -1 + {7'b0, ~cf_in}
        alu_cf_out = ~temp_cf_out;
      end
      4'b0100: begin
        {temp_cf_out, alu_out} = mode ? ~(a & b) : a + (a & ~b) + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b0101: begin
        {temp_cf_out, alu_out} = mode ? ~b : (a | b) + (a & ~b) + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b0110: begin
        {temp_cf_out, alu_out} = mode ? a ^ b : a - b - {7'b0, cf_in};
        alu_cf_out = temp_cf_out;
      end
      4'b0111: begin
        {temp_cf_out, alu_out} = mode ? a & ~b : a & ~b - {7'b0, cf_in};
        alu_cf_out = temp_cf_out;
      end
      4'b1000: begin
        {temp_cf_out, alu_out} = mode ? ~a | b : a + (a & b) + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b1001: begin
        {temp_cf_out, alu_out} = mode ? ~(a ^ b) : a + b + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b1010: begin
        {temp_cf_out, alu_out} = mode ? b : (a | ~b) + (a & b) + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b1011: begin
        {temp_cf_out, alu_out} = mode ? a & b : a & b - {7'b0, cf_in};
        alu_cf_out = temp_cf_out;
      end
      4'b1100: begin
        {temp_cf_out, alu_out} = mode ? 8'h01 : a + a + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b1101: begin
        {temp_cf_out, alu_out} = mode ? a | ~b : (a | b) + a + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b1110: begin
        {temp_cf_out, alu_out} = mode ? a | b : (a | ~b) + a + {7'b0, ~cf_in};
        alu_cf_out = ~temp_cf_out;
      end
      4'b1111: begin
        {temp_cf_out, alu_out} = mode ? a : a - {7'b0, cf_in};
        alu_cf_out = temp_cf_out;
      end
    endcase
  end


endmodule


memory.sv:
module memory #(
  parameter MEM_SIZE
)(
  input logic ce_n,
  input logic oe_n,
  input logic we_n,
  input logic [$clog2(MEM_SIZE) - 1 : 0] address,
  input logic [7:0] data_in,
  output logic [7:0] data_out
);

  logic [7:0] mem [MEM_SIZE - 1 : 0];

  assign data_out = !ce_n && !oe_n && we_n ? mem[address] : 'z;

  always @(ce_n, we_n, data_in) begin
    if(!ce_n && !we_n) mem[address] = data_in;
  end

endmodule


clock.sv:
module clock #(
  parameter FREQ = 2.75 // MHz
)(
	input logic arst,
	input logic stop_clk_req,
	output logic clk_out
);
  logic clk;
  logic stop_clk;
  real period = 1.0 / FREQ;
  real halfperiod = period / 2.0;

  initial begin
    clk = 1'b0;
    forever #(halfperiod / 2.0 * 1us) clk = ~clk; // Use halfperiod / 2 instead of halfperiod because clock_out is clk / 2
  end

  always @(negedge clk) begin
    stop_clk <= stop_clk_req;
  end

	always @(posedge clk, posedge arst) begin
    if(arst) clk_out <= 1'b1; // clock starts HIGH so that control bits can be written on the first falling edge.
		else if(!stop_clk) clk_out <= ~clk_out;
	end

endmodule



pa_microcode.sv:
  parameter byte unsigned base_u_rom8 = 8 * 8;
  parameter byte unsigned base_u_rom9 = 9 * 8;
  parameter byte unsigned base_u_rom10 = 10 * 8;
  parameter byte unsigned base_u_rom11 = 11 * 8;
  parameter byte unsigned base_u_rom12 = 12 * 8;
  parameter byte unsigned base_u_rom13 = 13 * 8;  
  
  // control word field positions
  parameter byte unsigned bitpos_typ0 = base_u_rom0 + 0;
  parameter byte unsigned bitpos_typ1 = base_u_rom0 + 1;
  parameter byte unsigned bitpos_offset_0 = base_u_rom0 + 2;
  parameter byte unsigned bitpos_offset_1 = base_u_rom0 + 3;
  parameter byte unsigned bitpos_offset_2 = base_u_rom0 + 4;
  parameter byte unsigned bitpos_offset_3 = base_u_rom0 + 5;
  parameter byte unsigned bitpos_offset_4 = base_u_rom0 + 6;
  parameter byte unsigned bitpos_offset_5 = base_u_rom0 + 7;
  
  parameter byte unsigned bitpos_offset_6 = base_u_rom1 + 0;
  parameter byte unsigned bitpos_cond_invert = base_u_rom1 + 1;
  parameter byte unsigned bitpos_cond_flag_src = base_u_rom1 + 2;
  parameter byte unsigned bitpos_cond_sel_0 = base_u_rom1 + 3;
  parameter byte unsigned bitpos_cond_sel_1 = base_u_rom1 + 4;
  parameter byte unsigned bitpos_cond_sel_2 = base_u_rom1 + 5;
  parameter byte unsigned bitpos_cond_sel_3 = base_u_rom1 + 6;
  parameter byte unsigned bitpos_escape = base_u_rom1 + 7;

  parameter byte unsigned bitpos_u_zf_in_src_0 = base_u_rom2 + 0;
  parameter byte unsigned bitpos_u_zf_in_src_1 = base_u_rom2 + 1;
  parameter byte unsigned bitpos_u_cf_in_src_0 = base_u_rom2 + 2;
  parameter byte unsigned bitpos_u_cf_in_src_1 = base_u_rom2 + 3;
  parameter byte unsigned bitpos_u_sf_in_src = base_u_rom2 + 4;
  parameter byte unsigned bitpos_u_of_in_src = base_u_rom2 + 5;
  parameter byte unsigned bitpos_ir_wrt = base_u_rom2 + 6;
  parameter byte unsigned bitpos_status_wrt = base_u_rom2 + 7;

  parameter byte unsigned bitpos_shift_src_0 = base_u_rom3 + 0;
  parameter byte unsigned bitpos_shift_src_1 = base_u_rom3 + 1;
  parameter byte unsigned bitpos_shift_src_2 = base_u_rom3 + 2;
  parameter byte unsigned bitpos_zbus_src_0 = base_u_rom3 + 3;
  parameter byte unsigned bitpos_zbus_src_1 = base_u_rom3 + 4;
  parameter byte unsigned bitpos_alu_a_src_0	= base_u_rom3 + 5;	
  parameter byte unsigned bitpos_alu_a_src_1	= base_u_rom3 + 6;	
  parameter byte unsigned bitpos_alu_a_src_2 = base_u_rom3 + 7; 

  parameter byte unsigned bitpos_alu_a_src_3 = base_u_rom4 + 0;
  parameter byte unsigned bitpos_alu_a_src_4 = base_u_rom4 + 1;
  parameter byte unsigned bitpos_alu_a_src_5 = base_u_rom4 + 2;
  parameter byte unsigned bitpos_alu_op_0 = base_u_rom4 + 3;
  parameter byte unsigned bitpos_alu_op_1 = base_u_rom4 + 4;
  parameter byte unsigned bitpos_alu_op_2 = base_u_rom4 + 5;
  parameter byte unsigned bitpos_alu_op_3 = base_u_rom4 + 6;
  parameter byte unsigned bitpos_alu_mode = base_u_rom4 + 7;

  parameter byte unsigned bitpos_alu_cf_in_src_0 = base_u_rom5 + 0;
  parameter byte unsigned bitpos_alu_cf_in_src_1 = base_u_rom5 + 1;
  parameter byte unsigned bitpos_alu_cf_in_invert = base_u_rom5 + 2;
  parameter byte unsigned bitpos_zf_in_src_0 = base_u_rom5 + 3;
  parameter byte unsigned bitpos_zf_in_src_1 = base_u_rom5 + 4;
  parameter byte unsigned bitpos_alu_cf_out_invert = base_u_rom5 + 5;
  parameter byte unsigned bitpos_cf_in_src_0 = base_u_rom5 + 6;
  parameter byte unsigned bitpos_cf_in_src_1 = base_u_rom5 + 7;

  parameter byte unsigned bitpos_cf_in_src_2 = base_u_rom6 + 0;
  parameter byte unsigned bitpos_sf_in_src_0 = base_u_rom6 + 1;
  parameter byte unsigned bitpos_sf_in_src_1 = base_u_rom6 + 2;
  parameter byte unsigned bitpos_of_in_src_0 = base_u_rom6 + 3;
  parameter byte unsigned bitpos_of_in_src_1 = base_u_rom6 + 4;
  parameter byte unsigned bitpos_of_in_src_2 = base_u_rom6 + 5;
  parameter byte unsigned bitpos_rd = base_u_rom6 + 6;
  parameter byte unsigned bitpos_wr = base_u_rom6 + 7;

  parameter byte unsigned bitpos_alu_b_src_0 = base_u_rom7 + 0;
  parameter byte unsigned bitpos_alu_b_src_1 = base_u_rom7 + 1;
  parameter byte unsigned bitpos_alu_b_src_2 = base_u_rom7 + 2;
  parameter byte unsigned bitpos_display_reg_load = base_u_rom7 + 3; // used during fetch to select and load register display
  parameter byte unsigned bitpos_dl_wrt = base_u_rom7 + 4;
  parameter byte unsigned bitpos_dh_wrt = base_u_rom7 + 5;
  parameter byte unsigned bitpos_cl_wrt = base_u_rom7 + 6;
  parameter byte unsigned bitpos_ch_wrt = base_u_rom7 + 7;

  parameter byte unsigned bitpos_bl_wrt = base_u_rom8 + 0;
  parameter byte unsigned bitpos_bh_wrt = base_u_rom8 + 1;
  parameter byte unsigned bitpos_al_wrt = base_u_rom8 + 2;
  parameter byte unsigned bitpos_ah_wrt = base_u_rom8 + 3;
  parameter byte unsigned bitpos_mdr_in_src = base_u_rom8 + 4;
  parameter byte unsigned bitpos_mdr_out_src = base_u_rom8 + 5;
  parameter byte unsigned bitpos_mdr_out_en = base_u_rom8 + 6;			// must invert before sending
  parameter byte unsigned bitpos_mdr_l_wrt = base_u_rom8 + 7;			

  parameter byte unsigned bitpos_mdr_h_wrt = base_u_rom9 + 0;
  parameter byte unsigned bitpos_tdr_l_wrt = base_u_rom9 + 1;
  parameter byte unsigned bitpos_tdr_h_wrt = base_u_rom9 + 2;
  parameter byte unsigned bitpos_di_l_wrt = base_u_rom9 + 3;
  parameter byte unsigned bitpos_di_h_wrt = base_u_rom9 + 4;
  parameter byte unsigned bitpos_si_l_wrt = base_u_rom9 + 5;
  parameter byte unsigned bitpos_si_h_wrt = base_u_rom9 + 6;
  parameter byte unsigned bitpos_mar_l_wrt = base_u_rom9 + 7;

  parameter byte unsigned bitpos_mar_h_wrt = base_u_rom10 + 0;
  parameter byte unsigned bitpos_bp_l_wrt = base_u_rom10 + 1;
  parameter byte unsigned bitpos_bp_h_wrt = base_u_rom10 + 2;
  parameter byte unsigned bitpos_pc_l_wrt = base_u_rom10 + 3;
  parameter byte unsigned bitpos_pc_h_wrt = base_u_rom10 + 4;
  parameter byte unsigned bitpos_sp_l_wrt = base_u_rom10 + 5;
  parameter byte unsigned bitpos_sp_h_wrt = base_u_rom10 + 6;
  //parameter byte unsigned bitpos_unused = base_u_rom10 + 7;

  //parameter byte unsigned bitpos_unused = base_u_rom11 + 0;
  parameter byte unsigned bitpos_int_vector_wrt = base_u_rom11 + 1;
  parameter byte unsigned bitpos_irq_masks_wrt = base_u_rom11 + 2;		// << wrt signals are also active low, 	
  parameter byte unsigned bitpos_mar_in_src = base_u_rom11 + 3;
  parameter byte unsigned bitpos_int_ack = base_u_rom11 + 4;		//--- active high
  parameter byte unsigned bitpos_clear_all_ints = base_u_rom11 + 5;
  parameter byte unsigned bitpos_ptb_wrt = base_u_rom11 + 6;
  parameter byte unsigned bitpos_page_table_we = base_u_rom11 + 7; 

  parameter byte unsigned bitpos_mdr_to_pagetable_data_en = base_u_rom12 + 0;
  parameter byte unsigned bitpos_force_user_ptb = base_u_rom12 + 1; // --->>> goes to board as page_table_addr_source via or gate
  //parameter byte unsigned bitpos_unused = base_u_rom12 + 2;
  //parameter byte unsigned bitpos_unused = base_u_rom12 + 3;
  //parameter byte unsigned bitpos_unused = base_u_rom12 + 4;
  //parameter byte unsigned bitpos_unused = base_u_rom12 + 5;
  parameter byte unsigned bitpos_gl_wrt = base_u_rom12 + 6;
  parameter byte unsigned bitpos_gh_wrt = base_u_rom12 + 7;

  parameter byte unsigned bitpos_immy_0 = base_u_rom13 + 0;
  parameter byte unsigned bitpos_immy_1 = base_u_rom13 + 1;
  parameter byte unsigned bitpos_immy_2 = base_u_rom13 + 2;
  parameter byte unsigned bitpos_immy_3 = base_u_rom13 + 3;
  parameter byte unsigned bitpos_immy_4 = base_u_rom13 + 4;
  parameter byte unsigned bitpos_immy_5 = base_u_rom13 + 5;
  parameter byte unsigned bitpos_immy_6 = base_u_rom13 + 6;
  parameter byte unsigned bitpos_immy_7 = base_u_rom13 + 7;
 
endpackage


pa_cpu.sv:
package pa_cpu;
  parameter PAGETABLE_RAM_SIZE = 2 ** 13;

  parameter byte unsigned bitpos_cpu_status_dma_ack = 0;
  parameter byte unsigned bitpos_cpu_status_irq_en = 1;
  parameter byte unsigned bitpos_cpu_status_mode = 2;
  parameter byte unsigned bitpos_cpu_status_paging_en = 3;
  parameter byte unsigned bitpos_cpu_status_halt = 4;
  parameter byte unsigned bitpos_cpu_status_displayreg_load = 5;
  // pos 6 undefined for now
  parameter byte unsigned bitpos_cpu_status_dir = 7;

  parameter byte unsigned bitpos_cpu_flags_zf = 0;
  parameter byte unsigned bitpos_cpu_flags_cf = 1;
  parameter byte unsigned bitpos_cpu_flags_sf = 2;
  parameter byte unsigned bitpos_cpu_flags_of = 3;

endpackage



Paulo Constantino - CC BY-NC-SA 4.0 DEED Attribution-NonCommercial-ShareAlike 4.0 International