From 0553c4839c06011bd044f69b4913e5c793fdd2ec Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sun, 27 Feb 2022 17:21:05 -0800 Subject: Initial commit. --- hdl/command_parser.sv | 109 +++++++ hdl/core.sv | 856 ++++++++++++++++++++++++++++++++++++++++++++++++++ hdl/defs.svh | 58 ++++ hdl/echo_arbiter.sv | 64 ++++ hdl/front_panel.sv | 211 +++++++++++++ hdl/pll.sv | 126 ++++++++ hdl/ram_controller.sv | 240 ++++++++++++++ hdl/result_printer.sv | 71 +++++ hdl/top.sv | 298 ++++++++++++++++++ 9 files changed, 2033 insertions(+) create mode 100644 hdl/command_parser.sv create mode 100644 hdl/core.sv create mode 100644 hdl/defs.svh create mode 100644 hdl/echo_arbiter.sv create mode 100644 hdl/front_panel.sv create mode 100644 hdl/pll.sv create mode 100644 hdl/ram_controller.sv create mode 100644 hdl/result_printer.sv create mode 100644 hdl/top.sv (limited to 'hdl') diff --git a/hdl/command_parser.sv b/hdl/command_parser.sv new file mode 100644 index 0000000..5c49db9 --- /dev/null +++ b/hdl/command_parser.sv @@ -0,0 +1,109 @@ +`include "defs.svh" + +module command_parser + #( TAG = 0 + ) ( input bit clock + , input bit reset + + , output bit uart_ready + , input bit uart_valid + , input uart_byte_t uart_data + + , input bit echo_ready + , output bit echo_valid + , output uart_byte_t echo_data + + , input bit command_ready + , output bit command_valid + , output ram_command_t command_data + ); + + bit input_byte_valid; + uart_byte_t input_byte; + + (* syn_encoding = "one-hot" *) enum int unsigned + { READ_ADDRESS_OR_COMMAND + , READ_DATA + } state; + + always @(posedge clock) begin + if (reset) begin + uart_ready = 0; + command_valid = 0; + input_byte_valid = 0; + input_byte = 0; + state = state.first; + end else begin + if (echo_ready) echo_valid = 0; + if (command_ready && command_valid) begin + command_valid = 0; + command_data.address = 0; + command_data.write = 0; + for (int i = 0; i < `RAM_LINE_WORDS; i = i + 1) begin + command_data.data[i] = 0; + command_data.mask[i] = ~0; + end + command_data.tag = TAG; + end + if (uart_ready && uart_valid) begin + echo_valid = 1; + echo_data = uart_data; + input_byte_valid = 1; + input_byte = uart_data; + end + + if (!command_valid && input_byte_valid) begin + case (state) + + READ_ADDRESS_OR_COMMAND: begin + if (input_byte >= "0" && input_byte <= "9") begin + command_data.address = command_data.address << 4; + command_data.address[$clog2(`RAM_LINE_WORDS)+:4] = input_byte - "0"; + end else if (input_byte >= "a" && input_byte <= "f") begin + command_data.address = command_data.address << 4; + command_data.address[$clog2(`RAM_LINE_WORDS)+:4] = input_byte - "a" + 10; + end else if (input_byte >= "A" && input_byte <= "F") begin + command_data.address = command_data.address << 4; + command_data.address[$clog2(`RAM_LINE_WORDS)+:4] = input_byte - "A" + 10; + end else if (input_byte == "?") begin + command_valid = 1; + command_data.write = 0; + command_data.data = 0; + end else if (input_byte == "=") begin + command_data.write = 1; + command_data.data = 0; + state = READ_DATA; + end else begin + command_data.address = 0; + command_data.write = 0; + command_data.data = 0; + end + end + + READ_DATA: begin + automatic bit [$bits(command_data.data)-1:0] flat_data = command_data.data; + flat_data = flat_data << 4; + if (input_byte >= "0" && input_byte <= "9") begin + flat_data[3:0] = input_byte - "0"; + command_data.data = flat_data; + end else if (input_byte >= "a" && input_byte <= "f") begin + flat_data[3:0] = input_byte - "a" + 10; + command_data.data = flat_data; + end else if (input_byte >= "A" && input_byte <= "F") begin + flat_data[3:0] = input_byte - "A" + 10; + command_data.data = flat_data; + end else begin + command_valid = 1; + state = state.first; + end + end + + endcase + input_byte_valid = 0; + end + + uart_ready = !echo_valid && !input_byte_valid; + end + end + +endmodule diff --git a/hdl/core.sv b/hdl/core.sv new file mode 100644 index 0000000..17b753d --- /dev/null +++ b/hdl/core.sv @@ -0,0 +1,856 @@ +`ifdef SYNTHESIS +`define lag(x) x +`else +`define lag(x) $past(x) +`endif + +module mem + ( input bit clk + , input bit reset + + , output bit ready + , input bit valid + , input bit write + , input bit [ADDR_BITS-1:0] address + , input bit [DATA_BITS-1:0] write_data + + , output bit read_valid + , output bit [DATA_BITS-1:0] read_data + ); + +parameter ADDR_BITS; +parameter DATA_BITS; +parameter INIT_FILE; + +bit [DATA_BITS-1:0] storage [0:(1<= 26000) $finish; + end +`endif + end + + if (switch_sing_step) + run = 0; + + if (state == FETCH && switch_sing_inst) + run = 0; + + rx_ready = !tti_valid; + end + end +end + +endmodule diff --git a/hdl/defs.svh b/hdl/defs.svh new file mode 100644 index 0000000..ea8dbc1 --- /dev/null +++ b/hdl/defs.svh @@ -0,0 +1,58 @@ +`define RAM_ADDRESS_BITS 23 +`define RAM_BYTE_BITS 8 +`define RAM_WORD_BYTES 2 +`define RAM_LINE_WORDS 1 + +`define PDP_ADDRESS_BITS 15 + +`define UART_BYTE_BITS 8 + +`define TAG_BITS 1 + +typedef bit [`RAM_ADDRESS_BITS-1:0] ram_word_address_t; +typedef bit [`RAM_ADDRESS_BITS-1:$clog2(`RAM_LINE_WORDS)] ram_line_address_t; +typedef bit [`RAM_BYTE_BITS-1:0] ram_byte_t; +typedef ram_byte_t [`RAM_WORD_BYTES-1:0] ram_word_t; +typedef ram_word_t [`RAM_LINE_WORDS-1:0] ram_line_t; +typedef bit [$clog2(`RAM_WORD_BYTES):0] ram_word_mask_t; +typedef ram_word_mask_t [`RAM_LINE_WORDS-1:0] ram_line_mask_t; + +typedef bit [$clog2(`RAM_WORD_BYTES+1):0] ram_byte_count_t; +typedef bit [$clog2(`RAM_LINE_WORDS+1):0] ram_word_count_t; + +typedef bit [`RAM_ADDRESS_BITS-1:`PDP_ADDRESS_BITS] ram_pdp_address_space_t; + +typedef bit [`PDP_ADDRESS_BITS-1:0] pdp_word_address_t; +typedef bit [`PDP_ADDRESS_BITS-1:$clog2(`RAM_LINE_WORDS)] pdp_line_address_t; + +typedef bit [`TAG_BITS-1:0] tag_t; + +typedef bit [`UART_BYTE_BITS-1:0] uart_byte_t; + +typedef struct { + ram_line_address_t address; + bit write; + ram_line_t data; + ram_line_mask_t mask; + tag_t tag; +} ram_command_t; + +typedef struct { + ram_line_address_t address; + ram_line_t data; + tag_t tag; +} ram_read_response_t; + +typedef struct { + pdp_line_address_t address; + bit write; + ram_line_t data; + ram_line_mask_t mask; + tag_t tag; +} pdp_command_t; + +typedef struct { + pdp_line_address_t address; + ram_line_t data; + tag_t tag; +} pdp_read_response_t; diff --git a/hdl/echo_arbiter.sv b/hdl/echo_arbiter.sv new file mode 100644 index 0000000..1c27e31 --- /dev/null +++ b/hdl/echo_arbiter.sv @@ -0,0 +1,64 @@ +`include "defs.svh" + +module echo_arbiter + ( input bit clock + , input bit reset + + , output bit in0_ready + , input bit in0_valid + , input uart_byte_t in0_data + + , output bit in1_ready + , input bit in1_valid + , input uart_byte_t in1_data + + , input bit out_ready + , output bit out_valid + , output uart_byte_t out_data + ); + + bit in0_hold_valid; + uart_byte_t in0_hold; + + bit in1_hold_valid; + uart_byte_t in1_hold; + + always @(posedge clock) begin + if (reset) begin + in0_ready = 0; + in1_ready = 0; + out_valid = 0; + out_data = 0; + in0_hold_valid = 0; + in0_hold = 0; + in1_hold_valid = 0; + in1_hold = 0; + end else begin + if (out_ready) out_valid = 0; + if (in0_ready && in0_valid) begin + in0_hold_valid = 1; + in0_hold = in0_data; + end + if (in1_ready && in1_valid) begin + in1_hold_valid = 1; + in1_hold = in1_data; + end + + if (!out_valid) begin + if (in0_hold_valid) begin + out_valid = 1; + out_data = in0_hold; + in0_hold_valid = 0; + end else if (in1_hold_valid) begin + out_valid = 1; + out_data = in1_hold; + in1_hold_valid = 0; + end + end + + in0_ready = !in0_hold_valid; + in1_ready = !in1_hold_valid; + end + end + +endmodule diff --git a/hdl/front_panel.sv b/hdl/front_panel.sv new file mode 100644 index 0000000..52b4bdb --- /dev/null +++ b/hdl/front_panel.sv @@ -0,0 +1,211 @@ +module front_panel + #( DEBOUNCE_MAX = 100 + ) + ( input bit clk + , input bit reset + + , input bit [8:1][12:1] led + , output bit [3:1][12:1] switch + + , inout wire [10:1] gpioa + , inout wire [28:13] gpiob + , inout wire [40:31] gpioc + ); + +localparam DEBOUNCE_BITS = $clog2(DEBOUNCE_MAX+1); + +enum + { LED_ROW1 + , DEAD_ROW2 + , LED_ROW2 + , DEAD_ROW3 + , LED_ROW3 + , DEAD_ROW4 + , LED_ROW4 + , DEAD_ROW5 + , LED_ROW5 + , DEAD_ROW6 + , LED_ROW6 + , DEAD_ROW7 + , LED_ROW7 + , DEAD_ROW8 + , LED_ROW8 + , DEAD_ROW9 + , SWITCH_PREP + , SWITCH_ROW1 + , SWITCH_ROW2 + , SWITCH_ROW3 + } state; + +bit [3:1][12:1] switch_raw; +bit [DEBOUNCE_BITS-1:0] switch_debounce; + +`define LEDROW1 gpioc[38] +`define LEDROW2 gpioc[40] +`define LEDROW3 gpiob[15] +`define LEDROW4 gpiob[16] +`define LEDROW5 gpiob[18] +`define LEDROW6 gpiob[22] +`define LEDROW7 gpioc[37] +`define LEDROW8 gpiob[13] + +`define SWROW1 gpioc[36] +`define SWROW2 gpioa[1] +`define SWROW3 gpioa[2] + +`define COL1 gpioa[8] +`define COL2 gpioa[10] +`define COL3 gpioa[7] +`define COL4 gpiob[27] +`define COL5 gpioc[31] +`define COL6 gpiob[26] +`define COL7 gpiob[24] +`define COL8 gpiob[21] +`define COL9 gpiob[19] +`define COL10 gpiob[23] +`define COL11 gpioc[32] +`define COL12 gpioc[33] + +`define DO_LEDS +`define DO_SWITCHES + +always_ff @(posedge clk) begin + // LED rows (active high) + `LEDROW1 = 1'b0; + `LEDROW2 = 1'b0; + `LEDROW3 = 1'b0; + `LEDROW4 = 1'b0; + `LEDROW5 = 1'b0; + `LEDROW6 = 1'b0; + `LEDROW7 = 1'b0; + `LEDROW8 = 1'b0; + + // Switch rows (active low) + `SWROW1 = 1'b1; + `SWROW2 = 1'b1; + `SWROW3 = 1'b1; + + if (reset) begin + switch = 0; + switch_raw = 0; + switch_debounce = 0; + state = state.first; + end else begin + automatic bit [3:1][12:1] new_switch = switch_raw; + + case (state) +`ifdef DO_LEDS +`define LED_ROW(n) \ + LED_ROW``n: begin \ + `LEDROW``n = 1'b1; \ + `COL1 = ~led[n][1]; \ + `COL2 = ~led[n][2]; \ + `COL3 = ~led[n][3]; \ + `COL4 = ~led[n][4]; \ + `COL5 = ~led[n][5]; \ + `COL6 = ~led[n][6]; \ + `COL7 = ~led[n][7]; \ + `COL8 = ~led[n][8]; \ + `COL9 = ~led[n][9]; \ + `COL10 = ~led[n][10]; \ + `COL11 = ~led[n][11]; \ + `COL12 = ~led[n][12]; \ + end + + `LED_ROW(1) + `LED_ROW(2) + `LED_ROW(3) + `LED_ROW(4) + `LED_ROW(5) + `LED_ROW(6) + `LED_ROW(7) + `LED_ROW(8) +`endif + +`ifdef DO_SWITCHES + SWITCH_PREP: begin + `SWROW1 = 1'b0; + + `COL1 = 1'bZ; + `COL2 = 1'bZ; + `COL3 = 1'bZ; + `COL4 = 1'bZ; + `COL5 = 1'bZ; + `COL6 = 1'bZ; + `COL7 = 1'bZ; + `COL8 = 1'bZ; + `COL9 = 1'bZ; + `COL10 = 1'bZ; + `COL11 = 1'bZ; + `COL12 = 1'bZ; + end + + SWITCH_ROW1: begin + `SWROW2 = 1'b0; + + new_switch[1][1] = ~`COL1; + new_switch[1][2] = ~`COL2; + new_switch[1][3] = ~`COL3; + new_switch[1][4] = ~`COL4; + new_switch[1][5] = ~`COL5; + new_switch[1][6] = ~`COL6; + new_switch[1][7] = ~`COL7; + new_switch[1][8] = ~`COL8; + new_switch[1][9] = ~`COL9; + new_switch[1][10] = ~`COL10; + new_switch[1][11] = ~`COL11; + new_switch[1][12] = ~`COL12; + end + + SWITCH_ROW2: begin + `SWROW3 = 1'b0; + + new_switch[2][1] = ~`COL1; + new_switch[2][2] = ~`COL2; + new_switch[2][3] = ~`COL3; + new_switch[2][4] = ~`COL4; + new_switch[2][5] = ~`COL5; + new_switch[2][6] = ~`COL6; + new_switch[2][7] = ~`COL7; + new_switch[2][8] = ~`COL8; + new_switch[2][9] = ~`COL9; + new_switch[2][10] = ~`COL10; + new_switch[2][11] = ~`COL11; + new_switch[2][12] = ~`COL12; + end + + SWITCH_ROW3: begin + new_switch[3][1] = ~`COL1; + new_switch[3][2] = ~`COL2; + new_switch[3][3] = ~`COL3; + new_switch[3][4] = ~`COL4; + new_switch[3][5] = ~`COL5; + new_switch[3][6] = ~`COL6; + new_switch[3][7] = ~`COL7; + new_switch[3][8] = ~`COL8; + new_switch[3][9] = ~`COL9; + new_switch[3][10] = ~`COL10; + new_switch[3][11] = ~`COL11; + new_switch[3][12] = ~`COL12; + end +`endif + endcase + + if (state == state.last) + state = state.first; + else + state = state.next; + + if (new_switch == switch_raw) begin + if (switch_debounce == 0) + switch = switch_raw; + else + --switch_debounce; + end else begin + switch_raw = new_switch; + switch_debounce = DEBOUNCE_MAX; + end + end +end + +endmodule diff --git a/hdl/pll.sv b/hdl/pll.sv new file mode 100644 index 0000000..d348b7c --- /dev/null +++ b/hdl/pll.sv @@ -0,0 +1,126 @@ +module pll + #( MULTIPLY_BY = 1 + , DIVIDE_BY = 1 + , NATIVE_PERIOD_PICOSECONDS = 20_000 + ) + ( input bit native_clk + , input bit reset_n + + , output bit target_clk + , output bit reset + ); + +enum + { NOT_LOCKED + , RESET_CYCLE + , READY + } state = state.first; + +bit locked; + +`ifndef SYNTHESIS + +assign target_clk = native_clk; +assign locked = 1; + +`else + +altpll + #( .clk0_divide_by(DIVIDE_BY) + , .clk0_multiply_by(MULTIPLY_BY) + , .inclk0_input_frequency(NATIVE_PERIOD_PICOSECONDS) + , .intended_device_family("Cyclone 10 LP") + , .operation_mode("NORMAL") + , .port_activeclock("PORT_UNUSED") + , .port_areset("PORT_USED") + , .port_clkbad0("PORT_UNUSED") + , .port_clkbad1("PORT_UNUSED") + , .port_clkloss("PORT_UNUSED") + , .port_clkswitch("PORT_UNUSED") + , .port_configupdate("PORT_UNUSED") + , .port_fbin("PORT_UNUSED") + , .port_inclk0("PORT_USED") + , .port_inclk1("PORT_UNUSED") + , .port_locked("PORT_USED") + , .port_pfdena("PORT_UNUSED") + , .port_phasecounterselect("PORT_UNUSED") + , .port_phasedone("PORT_UNUSED") + , .port_phasestep("PORT_UNUSED") + , .port_phaseupdown("PORT_UNUSED") + , .port_pllena("PORT_UNUSED") + , .port_scanaclr("PORT_UNUSED") + , .port_scanclk("PORT_UNUSED") + , .port_scanclkena("PORT_UNUSED") + , .port_scandata("PORT_UNUSED") + , .port_scandataout("PORT_UNUSED") + , .port_scandone("PORT_UNUSED") + , .port_scanread("PORT_UNUSED") + , .port_scanwrite("PORT_UNUSED") + , .port_clk0("PORT_USED") + , .port_clk1("PORT_UNUSED") + , .port_clk2("PORT_UNUSED") + , .port_clk3("PORT_UNUSED") + , .port_clk4("PORT_UNUSED") + , .port_clk5("PORT_UNUSED") + , .port_clkena0("PORT_UNUSED") + , .port_clkena1("PORT_UNUSED") + , .port_clkena2("PORT_UNUSED") + , .port_clkena3("PORT_UNUSED") + , .port_clkena4("PORT_UNUSED") + , .port_clkena5("PORT_UNUSED") + , .port_extclk0("PORT_UNUSED") + , .port_extclk1("PORT_UNUSED") + , .port_extclk2("PORT_UNUSED") + , .port_extclk3("PORT_UNUSED") + , .self_reset_on_loss_lock("ON") + , .width_clock(5) + ) pll + ( .areset(!reset_n) + , .inclk(native_clk) + , .clk(target_clk) + , .locked(locked) + , .activeclock() + , .clkbad() + , .clkena({6{1'b1}}) + , .clkloss() + , .clkswitch(1'b0) + , .configupdate(1'b0) + , .extclkena({4{1'b1}}) + , .fbin(1'b1) + , .fbmimicbidir() + , .fbout() + , .fref() + , .icdrclk() + , .pfdena(1'b1) + , .phasecounterselect({4{1'b1}}) + , .phasedone() + , .phasestep(1'b1) + , .phaseupdown(1'b1) + , .pllena(1'b1) + , .scanaclr(1'b0) + , .scanclk(1'b0) + , .scanclkena(1'b1) + , .scandata(1'b0) + , .scandataout() + , .scandone() + , .scanread(1'b0) + , .scanwrite(1'b0) + , .sclkout0() + , .sclkout1() + , .vcooverrange() + , .vcounderrange() + ); + +`endif + +always_ff @(posedge target_clk) begin + if (!reset_n || !locked) begin + state = state.first; + end else if (state != state.last) begin + state = state.next; + end + + reset = !(state == state.last); +end + +endmodule diff --git a/hdl/ram_controller.sv b/hdl/ram_controller.sv new file mode 100644 index 0000000..6eeb46d --- /dev/null +++ b/hdl/ram_controller.sv @@ -0,0 +1,240 @@ +`include "defs.svh" + +module ram_controller + ( input bit clock + , input bit reset + + , output bit command_ready + , input bit command_valid + , input ram_command_t command_data + + , input bit result_ready + , output bit result_valid + , output ram_read_response_t result_data + + , output bit ram_resetn + , output bit ram_csn + , output bit ram_clkp + , output bit ram_clkn + , output bit ram_rwds_oe + , input bit ram_rwds_in + , output bit ram_rwds_out + , output bit ram_data_oe + , input bit [7:0] ram_data_in + , output bit [7:0] ram_data_out + ); + + assign ram_clkn = !ram_clkp; + + bit valid; + ram_command_t command; + ram_word_address_t base_address; + + bit slow; + ram_word_count_t word_count; + + (* syn_encoding = "one-hot" *) enum int unsigned + { CHIP_SELECT + + , SEND_COMMAND_1 + , SEND_COMMAND_2 + , SEND_COMMAND_3 + , SEND_COMMAND_4 + , SEND_COMMAND_5 + , SEND_COMMAND_6 + + , LAT2_12 + , LAT2_11 + , LAT2_10 + , LAT2_9 + , LAT2_8 + , LAT2_7 + , LAT2_6 + , LAT2_5 + , LAT2_4 + , LAT2_3 + , LAT2_2 + , LAT2_1 + + /* Latency blocks are 6 cycle, but you start counting after the upper + * column address is sent (SEND_COMMAND_4) so we reduce the + * lowest-latency block by one full cycle (two states). + , LAT1_12 + , LAT1_11 + */ + , LAT1_10 + , LAT1_9 + , LAT1_8 + , LAT1_7 + , LAT1_6 + , LAT1_5 + , LAT1_4 + , LAT1_3 + , LAT1_2 + , LAT1_1 + + , DATA_1 + , DATA_2 + } state; + + (* syn_encoding = "compact" *) enum bit + { SETUP_OUTPUTS + , TOGGLE_CLOCK + } half_state; + + bit [2:0] reset_counter; + + bit prev_rwds; + + always @(posedge clock) begin + if (reset || reset_counter != 0) begin + command_ready = 0; + result_valid = 0; + ram_resetn = 0; + ram_csn = 1; + ram_clkp = 0; + ram_rwds_oe = 0; + ram_rwds_out = 0; + ram_data_oe = 0; + ram_data_out = 0; + base_address = 0; + slow = 0; + word_count = `RAM_LINE_WORDS; + state = state.first; + half_state = half_state.first; + if (reset) + reset_counter = 5; // Spec wants >= 100ns of reset + else + reset_counter = reset_counter - 1; + end else begin + ram_resetn = 1; + + if (result_ready) result_valid = 0; + if (command_ready && command_valid) begin + valid = 1; + command = command_data; + base_address = 0; + base_address[`RAM_ADDRESS_BITS-1:$clog2(`RAM_LINE_WORDS)] = command.address; + word_count = `RAM_LINE_WORDS; + state = state.first; + end + + if (!valid) begin + ram_rwds_oe = 0; + ram_data_oe = 0; + ram_csn = 1; + ram_clkp = 0; + end else if (half_state == TOGGLE_CLOCK) begin + half_state = half_state.next; + if (state != CHIP_SELECT && state != SEND_COMMAND_1) + ram_clkp = !ram_clkp; + end else if (half_state == SETUP_OUTPUTS) begin + automatic bit stall = 0; + half_state = half_state.next; + ram_rwds_oe = 0; + ram_data_oe = 0; + case (state) + + CHIP_SELECT: begin + ram_clkp = 0; // Overriding clock to guarantee that we're starting the command with the correct clock polarity + ram_csn = 0; + end + + SEND_COMMAND_1: begin + ram_data_oe = 1; + ram_data_out = {!command.write, 1'b0, 1'b1, 5'b0}; // R/W#, ADDRSPACE, BURST, RESERVED + end + + SEND_COMMAND_2: begin + ram_data_oe = 1; + ram_data_out = {4'b0, base_address[22:19]}; // RESERVED, ROW + end + + SEND_COMMAND_3: begin + ram_data_oe = 1; + ram_data_out = {base_address[18:11]}; // ROW + end + + SEND_COMMAND_4: begin + ram_data_oe = 1; + ram_data_out = {base_address[10:9], base_address[8:3]}; // ROW, UPPERCOL + // This is the cycle immediately before the latency countdown *really* begins. + // So we capture RWDS now in order to know how many latency blocks are required. + slow = ram_rwds_in; + end + + SEND_COMMAND_5: begin + ram_data_oe = 1; + ram_data_out = {8'b0}; // RESERVED + end + + SEND_COMMAND_6: begin + ram_data_oe = 1; + ram_data_out = {5'b0, base_address[2:0]}; // RESERVED, LOWERCOL + // If we're not in "slow" mode then skip the LAT2 latency + // block. Note that the state=state.next will still happen + // below, taking us to the first state in the LAT1 block. + if (!slow) state = LAT2_1; + end + + // Nothing happens on any of the LAT_* states except for + // cycling the clock and advancing state. + + DATA_1: begin + if (command.write) begin + ram_rwds_oe = 1; + ram_rwds_out = !command.mask[word_count - 1][0]; + ram_data_oe = 1; + ram_data_out = command.data[word_count - 1][0]; + end else if (prev_rwds != ram_rwds_in) begin + command.data[word_count - 1][0] = ram_data_in; + end else begin + stall = 1; + end + end + + DATA_2: begin + if (command.write) begin + ram_rwds_oe = 1; + ram_rwds_out = !command.mask[word_count - 1][1]; + ram_data_oe = 1; + ram_data_out = command.data[word_count - 1][1]; + word_count = word_count - 1; + if (word_count != 0) begin + stall = 1; + state = DATA_1; + end + end else if (prev_rwds != ram_rwds_in) begin + command.data[word_count - 1][1] = ram_data_in; + word_count = word_count - 1; + if (word_count != 0) begin + stall = 1; + state = DATA_1; + end + end else begin + stall = 1; + end + end + + endcase + if (!stall) begin + state = state.next; + if (state == state.first) begin + valid = 0; + if (!command.write) begin + // We know that this is safe because we don't accept commands unless we have result bandwidth + result_valid = 1; + result_data.address = command.address; + result_data.data = command.data; + result_data.tag = command.tag; + end + end + end + end + + prev_rwds = ram_rwds_in; + command_ready = !valid && !result_valid; + end + end + +endmodule diff --git a/hdl/result_printer.sv b/hdl/result_printer.sv new file mode 100644 index 0000000..3041e6e --- /dev/null +++ b/hdl/result_printer.sv @@ -0,0 +1,71 @@ +`include "defs.svh" + +module result_printer + #( TAG = 0 + ) ( input bit clock + , input bit reset + + , output bit result_ready + , input bit result_valid + , input ram_read_response_t result_data + + , input bit echo_ready + , output bit echo_valid + , output uart_byte_t echo_data + ); + + ram_read_response_t hold; + ram_byte_count_t byte_count; + ram_word_count_t word_count; + + (* syn_encoding = "one-hot" *) enum int unsigned + { HIGH_NIBBLE + , LOW_NIBBLE + } state; + + always @(posedge clock) begin + if (reset) begin + result_ready = 0; + echo_valid = 0; + echo_data = 0; + byte_count = 0; + word_count = 0; + state = state.first; + end else begin + if (echo_ready) echo_valid = 0; + if (result_ready && result_valid) begin + hold = result_data; + if (hold.tag == TAG) begin + byte_count = `RAM_WORD_BYTES; + word_count = `RAM_LINE_WORDS; + state = state.first; + end + end + + if (word_count != 0 && !echo_valid) begin + automatic ram_word_t w = hold.data[word_count-1]; + automatic ram_byte_t b = w[byte_count-1]; + echo_valid = 1; + case (state) + HIGH_NIBBLE: echo_data = b[7:4]; + LOW_NIBBLE: echo_data = b[3:0]; + endcase + if (echo_data < 10) + echo_data = echo_data + "0"; + else + echo_data = echo_data + "A" - 10; + state = state.next; + if (state == state.first) begin + byte_count = byte_count - 1; + if (byte_count == 0) begin + byte_count = `RAM_WORD_BYTES; + word_count = word_count - 1; + end + end + end + + result_ready = word_count == 0; + end + end + +endmodule diff --git a/hdl/top.sv b/hdl/top.sv new file mode 100644 index 0000000..7ec57b7 --- /dev/null +++ b/hdl/top.sv @@ -0,0 +1,298 @@ +`include "defs.svh" + +module top + ( input bit clock + , input bit resetn + + , inout wire [10:1] gpioa + , inout wire [28:13] gpiob + , inout wire [40:31] gpioc + + , output bit ram_resetn + , output bit ram_csn + , output bit ram_clkp + , output bit ram_clkn + , inout bit ram_rwds + , inout bit [7:0] ram_data + ); + + bit internal_clock; + bit internal_reset; + pll + #( .MULTIPLY_BY(1) + , .DIVIDE_BY(1) + ) fastpll + ( .native_clk(clock) + , .reset_n(resetn) + , .target_clk(internal_clock) + , .reset(internal_reset) + ); + + bit ram_rx_ready; + bit ram_rx_valid; + uart_byte_t ram_rx_data; + + bit ram_tx_ready; + bit ram_tx_valid; + uart_byte_t ram_tx_data; + + bit ram_echo_in0_ready; + bit ram_echo_in0_valid; + uart_byte_t ram_echo_in0_data; + + bit ram_echo_in1_ready; + bit ram_echo_in1_valid; + uart_byte_t ram_echo_in1_data; + + bit command_ready; + bit command_valid; + ram_command_t command_data; + + bit result_ready; + bit result_valid; + ram_read_response_t result_data; + + bit ram_rwds_oe; + bit ram_rwds_out; + assign ram_rwds = ram_rwds_oe ? ram_rwds_out : 1'bZ; + + bit ram_data_oe; + bit [7:0] ram_data_out; + assign ram_data = ram_data_oe ? ram_data_out : 8'bZ; + + alt_jtag_atlantic + #( .INSTANCE_ID(0) + , .LOG2_RXFIFO_DEPTH(6) + , .LOG2_TXFIFO_DEPTH(6) + , .SLD_AUTO_INSTANCE_INDEX("NO") + ) ram_jtag + ( .clk(internal_clock) + , .rst_n(!internal_reset) + + , .r_dat(ram_tx_data) + , .r_val(ram_tx_valid) + , .r_ena(ram_tx_ready) + + , .t_dat(ram_rx_data) + , .t_dav(ram_rx_ready) + , .t_ena(ram_rx_valid) + ); + + echo_arbiter arb + ( .clock(internal_clock) + , .reset(internal_reset) + + , .in0_ready(ram_echo_in0_ready) + , .in0_valid(ram_echo_in0_valid) + , .in0_data(ram_echo_in0_data) + + , .in1_ready(ram_echo_in1_ready) + , .in1_valid(ram_echo_in1_valid) + , .in1_data(ram_echo_in1_data) + + , .out_ready(ram_tx_ready) + , .out_valid(ram_tx_valid) + , .out_data(ram_tx_data) + ); + + command_parser + #( .TAG(0) + ) parser + ( .clock(internal_clock) + , .reset(internal_reset) + + , .uart_ready(ram_rx_ready) + , .uart_valid(ram_rx_valid) + , .uart_data(ram_rx_data) + + , .echo_ready(ram_echo_in0_ready) + , .echo_valid(ram_echo_in0_valid) + , .echo_data(ram_echo_in0_data) + + , .command_ready(command_ready) + , .command_valid(command_valid) + , .command_data(command_data) + ); + + ram_controller ram + ( .clock(internal_clock) + , .reset(internal_reset) + + , .command_ready(command_ready) + , .command_valid(command_valid) + , .command_data(command_data) + + , .result_ready(result_ready) + , .result_valid(result_valid) + , .result_data(result_data) + + , .ram_resetn(ram_resetn) + , .ram_csn(ram_csn) + , .ram_clkp(ram_clkp) + , .ram_clkn(ram_clkn) + , .ram_rwds_oe(ram_rwds_oe) + , .ram_rwds_in(ram_rwds) + , .ram_rwds_out(ram_rwds_out) + , .ram_data_oe(ram_data_oe) + , .ram_data_in(ram_data) + , .ram_data_out(ram_data_out) + ); + + result_printer + #( .TAG(0) + ) print + ( .clock(internal_clock) + , .reset(internal_reset) + + , .result_ready(result_ready) + , .result_valid(result_valid) + , .result_data(result_data) + + , .echo_ready(ram_echo_in1_ready) + , .echo_valid(ram_echo_in1_valid) + , .echo_data(ram_echo_in1_data) + ); + + bit slow_clock; + bit slow_reset; + pll + #( .MULTIPLY_BY(1) + , .DIVIDE_BY(500) + ) slowpll + ( .native_clk(clock) + , .reset_n(resetn) + , .target_clk(slow_clock) + , .reset(slow_reset) + ); + + bit [8:1][12:1] led; + bit [3:1][12:1] switch; + + front_panel panel + ( .clk(slow_clock) + , .reset(slow_reset) + + , .led(led) + , .switch(switch) + + , .gpioa(gpioa) + , .gpiob(gpiob) + , .gpioc(gpioc) + ); + + bit [2:0] switch_df; + bit [2:0] switch_if; + bit [11:0] switch_sr; + bit switch_start; + bit switch_load_add; + bit switch_dep; + bit switch_exam; + bit switch_cont; + bit switch_stop; + bit switch_sing_step; + bit switch_sing_inst; + + // Note that we are reversing the order here on a number of aggregates because + // the panel model gives us LEDs and switches in schematic-order, which is the + // opposite of the bit order + assign switch_df = {switch[2][1], switch[2][2], switch[2][3]}; + assign switch_if = {switch[2][4], switch[2][5], switch[2][6]}; + assign switch_sr = {switch[1][1], switch[1][2], switch[1][3], switch[1][4], switch[1][5], switch[1][6], switch[1][7], switch[1][8], switch[1][9], switch[1][10], switch[1][11], switch[1][12]}; + assign switch_start = switch[3][1]; + assign switch_load_add = switch[3][2]; + assign switch_dep = switch[3][3]; + assign switch_exam = switch[3][4]; + assign switch_cont = switch[3][5]; + assign switch_stop = switch[3][6]; + `ifdef HISTORIC_SWITCH_BEHAVIOUR + assign switch_sing_step = !switch[3][7]; + assign switch_sing_inst = !switch[3][8]; + `else + assign switch_sing_step = switch[3][7]; + assign switch_sing_inst = switch[3][8]; + `endif + + bit [11:0] led_pc; + bit [11:0] led_memaddr; + bit [11:0] led_memdata; + bit [11:0] led_acc; + bit [11:0] led_mq; + bit led_and; + bit led_tad; + bit led_isz; + bit led_dca; + bit led_jms; + bit led_jmp; + bit led_iot; + bit led_opr; + bit led_fetch; + bit led_execute; + bit led_defer; + bit led_word_count; + bit led_current_address; + bit led_break; + bit led_ion; + bit led_pause; + bit led_run; + bit [4:0] led_step_counter; + bit [2:0] led_df; + bit [2:0] led_if; + bit led_link; + + // Note that we are reversing the order here on a number of aggregates because + // the panel model gives us LEDs and switches in schematic-order, which is the + // opposite of the bit order + assign led[1] = {led_pc[0], led_pc[1], led_pc[2], led_pc[3], led_pc[4], led_pc[5], led_pc[6], led_pc[7], led_pc[8], led_pc[9], led_pc[10], led_pc[11]}; + assign led[2] = {led_memaddr[0], led_memaddr[1], led_memaddr[2], led_memaddr[3], led_memaddr[4], led_memaddr[5], led_memaddr[6], led_memaddr[7], led_memaddr[8], led_memaddr[9], led_memaddr[10], led_memaddr[11]}; + assign led[3] = {led_memdata[0], led_memdata[1], led_memdata[2], led_memdata[3], led_memdata[4], led_memdata[5], led_memdata[6], led_memdata[7], led_memdata[8], led_memdata[9], led_memdata[10], led_memdata[11]}; + assign led[4] = {led_acc[0], led_acc[1], led_acc[2], led_acc[3], led_acc[4], led_acc[5], led_acc[6], led_acc[7], led_acc[8], led_acc[9], led_acc[10], led_acc[11]}; + assign led[5] = {led_mq[0], led_mq[1], led_mq[2], led_mq[3], led_mq[4], led_mq[5], led_mq[6], led_mq[7], led_mq[8], led_mq[9], led_mq[10], led_mq[11]}; + assign led[6] = {led_word_count, led_defer, led_execute, led_fetch, led_opr, led_iot, led_jmp, led_jms, led_dca, led_isz, led_tad, led_and}; + assign led[7] = {2'b0, led_step_counter[4], led_step_counter[3], led_step_counter[2], led_step_counter[1], led_step_counter[0], led_run, led_pause, led_ion, led_break, led_current_address}; + assign led[8] = {5'b0, led_link, led_if[0], led_if[1], led_if[2], led_df[0], led_df[1], led_df[2]}; + + core cpu + ( .clk(internal_clock) + , .reset(internal_reset) + + , .switch_df(switch_df) + , .switch_if(switch_if) + , .switch_sr(switch_sr) + , .switch_start(switch_start) + , .switch_load_add(switch_load_add) + , .switch_dep(switch_dep) + , .switch_exam(switch_exam) + , .switch_cont(switch_cont) + , .switch_stop(switch_stop) + , .switch_sing_step(switch_sing_step) + , .switch_sing_inst(switch_sing_inst) + + , .led_pc(led_pc) + , .led_memaddr(led_memaddr) + , .led_memdata(led_memdata) + , .led_acc(led_acc) + , .led_mq(led_mq) + , .led_and(led_and) + , .led_tad(led_tad) + , .led_isz(led_isz) + , .led_dca(led_dca) + , .led_jms(led_jms) + , .led_jmp(led_jmp) + , .led_iot(led_iot) + , .led_opr(led_opr) + , .led_fetch(led_fetch) + , .led_execute(led_execute) + , .led_defer(led_defer) + , .led_word_count(led_word_count) + , .led_current_address(led_current_address) + , .led_break(led_break) + , .led_ion(led_ion) + , .led_pause(led_pause) + , .led_run(led_run) + , .led_step_counter(led_step_counter) + , .led_df(led_df) + , .led_if(led_if) + , .led_link(led_link) + ); + +endmodule -- cgit v1.2.3