// represents the Ben Eater 8bit computer `timescale 1us/1us `include "eater_types.sv" module eater_computer( // clock input input wire clk_in, // Whether to automatically run (vs manual control) input wire auto_run_in, // current content of the bus output wire [7:0] debug_bus ); /* verilator public_on */ // bus: can contain anything - multi driver, thus tri. tri0 [7:0] bus; assign debug_bus = bus; wire [7:0] // Always-output for A (-> ALU) A_out, // Always-output for B (-> ALU) B_out, // Always-output for RAM // (buffered separately, since I'm re-using code) RAM_out, // Always-output for INStruction register (which is "split" into MSB and LSB) // (buffered separately) INS_out, // Always-output for Memory Address Register. // feeds into RAM, at least the LSB. MAR_out, // PC is only 4 bit, but to output to bus, we want to pad with 0es. PC_out_full, // OUT->Display output OUT_out ; // PC is only 4 bit. wire [3:0] PC_in, PC_out; CpuControlFlags manual_flags; wire CpuControlFlags automatic_flags; wire CpuControlFlags flags; assign flags = auto_run_in ? automatic_flags : manual_flags; /* verilator public_off */ eater_register A ( .clk_in(clk_in), .en_store_in(flags.A_in), .en_output_in(flags.A_out), .data_in(bus), .bus_out(bus), .always_out(A_out) // .data(bus) ); eater_register B ( .clk_in(clk_in), .en_store_in(flags.B_in), .en_output_in(flags.B_out), .data_in(bus), .bus_out(bus), .always_out(B_out) // .data(bus) ); eater_register INS ( .clk_in(clk_in), .en_store_in(flags.INS_in), .en_output_in(flags.INS_out), .data_in(bus), .bus_out(), .always_out(INS_out) ); // 4 LSB go from INS to BUS wire [7:0] INS_to_bus_interm = {4'b0, INS_out[3:0]}; // TODO: 4 MSB go to decoder, to be implemented. zbuffer INS_to_bus_buffer ( .data_in(INS_to_bus_interm), .en_output_in(flags.INS_out), .data_out(bus) ); eater_register MEM_ADR ( .clk_in(clk_in), .en_store_in(flags.MAR_in), .en_output_in(1'b0), .data_in(bus), .bus_out(), .always_out(MAR_out) // .data(mem_adr_bus_out) ); wire [3:0] RAM_adr_in = MAR_out[3:0]; // Eater RAM is "technically" synchronous, but still enables write on clk & w_en. // However, "my RAM" *always outputs something*, and that's not expected. // buffer separately. my_mem #( .DATA_WIDTH(8), .DATA_DEPTH(16) ) RAM ( .clk_i(clk_in), .write_en_i(flags.RAM_in), // doesn't matter .read_en_i(), .r_read_addr(RAM_adr_in), .r_write_addr(RAM_adr_in), .data_i(bus), .data_o(), .async_data_o(RAM_out) ); zbuffer ram_to_bus_buffer ( .data_in(RAM_out), .en_output_in(flags.RAM_out), .data_out(bus) ); eater_alu alu ( .clk_in(clk_in), .en_output_in(flags.ALU_out), .A_in(A_out), .B_in(B_out), .subtract_n_add_in(flags.ALU_subtract_nadd), .bus_out(bus) ); assign PC_in = bus[3:0]; wire PC_clk_neg = ~clk_in; counter #( .DATA_WIDTH(4) ) PC ( .clk_in(PC_clk_neg), .X_in(PC_in), .st_store_X_in(flags.PC_in), .count_enable_in(flags.PC_count), .counter_out(PC_out) ); assign PC_out_full = {4'b0, PC_out}; zbuffer PC_to_bus_buffer ( .data_in(PC_out_full), .en_output_in(flags.PC_out), .data_out(bus) ); eater_register OUT ( .clk_in(clk_in), .data_in(bus), .en_store_in(flags.OUT_in), .en_output_in(1'b0), .bus_out(), .always_out(OUT_out) ); eater_decoder decoder ( .clk_i(clk_in), .instruction_i(INS_out), .flags_o(automatic_flags) ); endmodule