/* (c) Raphaƫl Jacquot 2019 This file is part of hp_saturn. hp_saturn is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. hp_saturn is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Foobar. If not, see . */ `default_nettype none module saturn_bus ( i_clk, i_clk_en, i_reset, o_halt, o_phase, o_cycle_ctr, o_instr_decoded, o_debug_cycle, o_char_to_send, o_char_counter, o_char_valid, o_char_send, i_serial_busy ); input wire [0:0] i_clk; input wire [0:0] i_clk_en; input wire [0:0] i_reset; output wire [0:0] o_halt; output wire [1:0] o_phase; output wire [31:0] o_cycle_ctr; output wire [0:0] o_instr_decoded; output wire [0:0] o_debug_cycle; assign o_debug_cycle = dbg_debug_cycle; output wire [7:0] o_char_to_send; output wire [9:0] o_char_counter; output wire [0:0] o_char_valid; output wire [0:0] o_char_send; input wire [0:0] i_serial_busy; assign o_phase = phase; assign o_cycle_ctr = cycle_ctr; /************************************************************************************************** * * this is the main firmware rom module * this module is always active, there is no configuration. * *************************************************************************************************/ saturn_hp48gx_rom hp48gx_rom ( .i_clk (i_clk), .i_clk_en (i_clk_en), .i_reset (i_reset), `ifdef SIM .i_phase (phase), .i_cycle_ctr (cycle_ctr), `endif .i_phase_0 (phases[0]), .i_debug_cycle (dbg_debug_cycle), .i_bus_clk_en (bus_clk_en), .i_bus_is_data (ctrl_bus_is_data), .o_bus_nibble_out (rom_bus_nibble_out), .i_bus_nibble_in (ctrl_bus_nibble_out) ); wire [3:0] rom_bus_nibble_out; /************************************************************************************************** * * the main processor is hidden behind this bus controller device * * *************************************************************************************************/ saturn_bus_controller bus_controller ( .i_clk (i_clk), .i_clk_en (i_clk_en), .i_reset (i_reset), .i_phases (phases), .i_phase (phase), .i_cycle_ctr (cycle_ctr), .o_bus_clk_en (ctrl_bus_clk_en), .o_bus_is_data (ctrl_bus_is_data), .o_bus_nibble_out (ctrl_bus_nibble_out), .i_bus_nibble_in (ctrl_bus_nibble_in), // more ports should show up to allow for output to the serial port of debug information .o_debug_cycle (dbg_debug_cycle), .o_instr_decoded (o_instr_decoded), .o_char_to_send (o_char_to_send), .o_char_counter (o_char_counter), .o_char_valid (o_char_valid), .o_char_send (o_char_send), .i_serial_busy (i_serial_busy), .o_halt (ctrl_halt) ); wire [0:0] ctrl_bus_clk_en; wire [0:0] ctrl_bus_is_data; wire [3:0] ctrl_bus_nibble_out; reg [3:0] ctrl_bus_nibble_in; wire [0:0] dbg_debug_cycle; wire [0:0] ctrl_halt; /************************************************************************************************** * * priority logic for the bus * * *************************************************************************************************/ reg [0:0] bus_halt; reg [3:0] phases; reg [1:0] phase; reg [31:0] cycle_ctr; wire [0:0] bus_clk_en = i_clk_en && ctrl_bus_clk_en; initial begin bus_halt = 1'b0; phases = 4'b1; cycle_ctr = 32'd0; end assign o_halt = bus_halt || ctrl_halt; /* handles modules priority * goes through all modules * if the module is active, this is the one giving out it's data * the last active module wins */ always @(*) begin ctrl_bus_nibble_in = rom_bus_nibble_out; end always @(*) begin phase = 2'd0; if (phases[1]) phase = 2'd1; if (phases[2]) phase = 2'd2; if (phases[3]) phase = 2'd3; end always @(posedge i_clk) begin /* if we're not debugging, advance phase on each clock */ if (!dbg_debug_cycle && i_clk_en) begin phases <= {phases[2:0], phases[3]}; /* using phases[3] here becase it will be phase_0 on the next step, * so we get to a new cycle on the first phase... */ cycle_ctr <= cycle_ctr + {31'b0, phases[3]}; end `ifdef SIM if (cycle_ctr == 136) begin bus_halt <= 1'b1; $display("BUS %0d: [%d] enough cycles for now", phase, cycle_ctr); end `endif if (i_reset) begin bus_halt <= 1'b0; phases <= 4'b1; cycle_ctr <= 32'd0; end end endmodule