diff --git a/Makefile b/Makefile index 700b339..3721846 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ SRC_DIR=. BUILD_DIR=build OUTPUT_DIR=output -.PHONY: clean test all run_ping_pong all_programs_binary all_programs_resolved +.PHONY: clean test all run_verilog_io run_ping_pong all_programs_binary all_programs_resolved output_rom_binaries -all: all_programs_binary all_programs_resolved +all: all_programs_binary all_programs_resolved verilog_modules clean: rm -rf $(BUILD_DIR) @@ -19,6 +19,8 @@ test: pytest test_verilog_modules all_programs_binary: $(patsubst programs/%.asm, $(OUTPUT_DIR)/programs/%.bin, $(shell find programs/ -name '*.asm')) +output_rom_binaries: $(OUTPUT_DIR)/programs/boot_sequence.bin $(OUTPUT_DIR)/programs/ping_pong.bin + $(OUTPUT_DIR)/programs/%.bin: programs/%.asm mkdir -p $(dir $@) python3 -m planner asm -b $^ > $@ @@ -31,3 +33,6 @@ $(OUTPUT_DIR)/programs/%_resolved.asm: programs/%.asm run_ping_pong: python3 -m planner compile_and_execute ping_pong + +run_verilog_io: + python3 -m planner verilog_io diff --git a/README.md b/README.md index 38b2928..68b52bd 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,13 @@ The eventual goal(?) is to build a general-purpose processor integrated with sim ## Sample Programs * Ping Pong + * 16x8 LED display with W/S/Up/Down keyboard controller * Source: [ping_pong.asm](programs/ping_pong.asm) * Generate resolved assembly: `python3 -m planner asm -r programs/ping_pong.asm` [[example](output/programs/ping_pong_resolved.asm)] * Generate binary: `python3 -m planner asm -b programs/ping_pong.asm` [[example](output/programs/ping_pong.bin)] - * Run on emulator: `python3 -m planner compile_and_execute ping_pong` - * 16x8 LED display with W/S/Up/Down keyboard controller + * Run on python emulator: `python3 -m planner compile_and_execute ping_pong` * ![image](https://github.com/user-attachments/assets/9fa2f68f-73ae-465c-a29c-cc92b0dc421a) + * Run on verilog emulator: `make verilog_simulate` ## Design diff --git a/emulator/Makefile.mk b/emulator/Makefile.mk index 1b65703..e5b1bdb 100644 --- a/emulator/Makefile.mk +++ b/emulator/Makefile.mk @@ -1,11 +1,25 @@ BUILD_EMULATOR = $(BUILD_DIR)/emulator SRC_EMULATOR = $(SRC_DIR)/emulator -.PHONY: test_verilog_modules +.PHONY: verilog_modules test_verilog_modules verilog_data_prerequisites verilog_simulate -$(BUILD_EMULATOR)/%_test: $(SRC_EMULATOR)/%_test.v +$(BUILD_EMULATOR)/%_test: $(SRC_EMULATOR)/%_test.v $(SRC_EMULATOR)/%.v mkdir -p $(dir $@) - iverilog -o $@ $^ + iverilog -o $@ $< + +verilog_modules: $(BUILD_EMULATOR)/executable_chipset $(patsubst $(SRC_EMULATOR)/%_test.v, $(BUILD_EMULATOR)/%_test, $(shell find $(SRC_EMULATOR) -name '*_test.v')) + mkdir -p $(BUILD_EMULATOR)/io + +verilog_data_prerequisites: output_rom_binaries test_verilog_modules: $(patsubst $(SRC_EMULATOR)/%_test.v, $(BUILD_EMULATOR)/%_test, $(shell find $(SRC_EMULATOR) -name '*_test.v')) + $(MAKE) verilog_data_prerequisites $(foreach test_name, $^, echo "Executing $(test_name)" && ./$(test_name)) + +$(BUILD_EMULATOR)/executable_chipset: $(SRC_EMULATOR)/executable_chipset.v + $(MAKE) verilog_data_prerequisites + mkdir -p $(dir $@) + iverilog -o $@ $^ + +verilog_simulate: $(BUILD_EMULATOR)/executable_chipset + ./$^ | $(MAKE) run_verilog_io diff --git a/emulator/chipset.v b/emulator/chipset.v index cb67033..df9f104 100644 --- a/emulator/chipset.v +++ b/emulator/chipset.v @@ -1,128 +1,233 @@ -`include "emulator/module/clock.v" - -module CHIPSET(); - // Global Registers - reg execute_from_brom; - - // Stages +`include "emulator/com/mux.v" +`include "emulator/com/stage0.v" +`include "emulator/com/stage1.v" +`include "emulator/com/stage2.v" +`include "emulator/com/stage3.v" +`include "emulator/com/rom.v" +`include "emulator/seq/clock.v" +`include "emulator/seq/register.v" +`include "emulator/seq/io_devices.v" +`include "emulator/seq/ram.v" + +module CHIPSET( + output is_powered_on, + output[15:0] pc, + output flag_execute_from_ram, + input reset_button); + // wire is_powered_on; + // wire flag_execute_from_ram; + wire flag_last_zero; + // wire[15:0] pc; + + // Clock wire[0:3] clk; - wire[0:3] is_stage; + wire[1:0] clk_stage; CLOCK clock( .clk(clk[0:3]), - .is_stage(is_stage[0:3])); - - // Boot Sequence - // - // When the device have power supply but `is_powered_on` is off. The pc_eval - // forces `program_counter_next` to be 0 and `execute_from_brom` to True. - // If we keep the `is_powered_on` button in off stage for at-least 4 cycles - // then at "stage3 posedge" program_counter should get updated to 0. - // After that for every "stage0 posedge" till is_powered_on is off, - // program_counter:0 along with execute_from_brom:True will be used to pull - // up and execute first instruction from BROM. - // - // Assumption: No stateful IO devices are connected. - // TODO: Implement `execute_from_brom` update implementation. - wire is_powered_on; - BOOT_CONTROL boot_control(.is_powered_on(is_powered_on)); - - - // MBLOCK is a continous circuit and doesn't depend on clock - // but the behaviour do depend on stage which is abstracted. - wire[15:0] program_counter; - wire[1:0] mblock_selector; - wire[15:0] mblock_address; - wire[31:0] mblock_input; - wire[31:0] mblock_output; - wire mblock_write; - - MBLOCK_MUX mblock_mux( - .mblock_address(mblock_address[15:0]), - .mblock_selector(mblock_selector[1:0]), - .execute_from_brom(execute_from_brom), - .is_stage(is_stage[0:3]), - .address0(program_counter), - .address1(v0_source), - .address2(v1_source), - .address3(v2_source), - .is_write(4'b0000)); - - MBLOCK mblock( - .out(mblock_output), - .selector(mblock_selector), - .in(mblock_input), - .address(mblock_address), - .is_write(mblock_write)); + .clk_stage(clk_stage)); + + // BROM + wire[15:0] brom_address; + wire[31:0] brom_value; + ROM_BOOT #(.filename("output/programs/boot_sequence.bin")) + brom(.out(brom_value), .address(brom_address)); + + // RAM + wire ram_is_write; + wire[15:0] ram_address; + wire[31:0] ram_in; + wire[31:0] ram_value; + RAM_32bit_16aline ram( + .out(ram_value), + .in(ram_in), + .address(ram_address), + .is_write(ram_is_write), + .clk(clk[3])); + + wire[15:0] ram_address_stage0; + wire[15:0] ram_address_stage1; + wire[15:0] ram_address_stage2; + wire[15:0] ram_address_stage3; + MUX_2_16b ram_address_selector( + .value(ram_address), + .A0(ram_address_stage0), + .A1(ram_address_stage1), + .A2(ram_address_stage2), + .A3(ram_address_stage3), + .S(clk_stage)); + // always @(ram_address, ram_address_stage0, ram_address_stage1, ram_address_stage2, ram_address_stage3, clk_stage) + // begin + // $display("add:%b, s0:%b, s1:%b, s2:%b, s3:%b, stage:%b", ram_address, ram_address_stage0, ram_address_stage1, ram_address_stage2, ram_address_stage3, clk_stage); + // end + + // IO Devices + wire[7:0] io_device_id_s1; + wire[7:0] io_device_id_s3; + wire[7:0] io_device_id; + wire[31:0] input_devices_value; + wire[31:0] output_devices_value; + wire output_is_write; + + IODevices io_devices( + .value_out(input_devices_value), + .device_id(io_device_id), + .value_in(output_devices_value), + .is_write(output_is_write), + .clk(clk[3])); + + wire[7:0] unused2; + MUX_1_16b io_device_id_selector( + .value({unused2, io_device_id}), + .A0({unused2, io_device_id_s1}), + .A1({unused2, io_device_id_s3}), + .S(clk_stage[1])); // STAGE0 - - // TODO: Ensure MBLOCK supplies expectations. - // MBLOCK_MUX is expected to fetch MBLOCK at `program_counter` from - // BROM / RAM based on `execute_from_brom` and redirect the value - // to full_ins via mblock_output. - - // @stage0 posedge following values should freeze. - wire[7:0] v0_source, v1_source, v2_source, instruction_op; - INS_RESOLVER stage0( - .v0(v0_source), .v1(v1_source), .v2(v2_source), .op(instruction_op), - .full_ins(.mblock_output), - clk[0]); + wire[31:0] _instruction_binary; + STAGE0 stage0( + .instruction_binary(_instruction_binary), + .ram_address(ram_address_stage0), + .brom_address(brom_address), + .ram_value(ram_value), + .brom_value(brom_value), + .pc(pc), + .execute_from_ram(flag_execute_from_ram)); // STAGE1 - - // TODO: Breakdown instruction_op into sub-operations - - // TODO: Ensure MBLOCK supplies expectations. - // MBLOCK_MUX is expected to fetch MBLOCK based on v0_source and - // instruction_op breakdowns and redirect the value into v0. - - // @stage1 posedge following should freeze. - wire[31:0] v0; - FETCH_AND_STORE stage1( - .value(v0), - .in(mblock_output), + wire[31:0] instruction_binary; + REGISTER_up_16b stage1_r0( + .out(instruction_binary[31:16]), + .in(_instruction_binary[31:16]), + .clk(clk[1])); + REGISTER_up_16b stage1_r1( + .out(instruction_binary[15:0]), + .in(_instruction_binary[15:0]), .clk(clk[1])); - // STAGE2 - - // TODO: Ensure MBLOCK supplies expectations. - // MBLOCK_MUX is expected to fetch MBLOCK based on v0_source and - // instruction_op breakdowns and redirect the value into v0. + wire[3:0] mblock_alu_op = instruction_binary[3:0]; + wire[1:0] mblock_s1 = instruction_binary[5:4]; + wire[2:0] mblock_s2 = instruction_binary[8:6]; + wire[2:0] mblock_s3 = instruction_binary[11:9]; + wire[7:0] vrw_source = instruction_binary[23:16]; + wire[7:0] vr_source = instruction_binary[31:24]; + + wire[31:0] _vr_value; + STAGE1 stage1( + .vr_value(_vr_value), + .io_device_id(io_device_id_s1), + .ram_address(ram_address_stage1), + .mblock_s1(mblock_s1), + .vr_source(vr_source), + .input_devices_value(input_devices_value), + .ram_value(ram_value)); - // @stage2 posedge following should freeze. - wire[31:0] v1; - FETCH_AND_STORE stage2( - .value(v1), - .in(mblock_output), - .clk(clk2)); + // STAGE2 + wire[31:0] vr_value; + REGISTER_up_16b stage2_r0( + .out(vr_value[31:16]), + .in(_vr_value[31:16]), + .clk(clk[2])); + REGISTER_up_16b stage2_r1( + .out(vr_value[15:0]), + .in(_vr_value[15:0]), + .clk(clk[2])); + + wire[31:0] _vrw_value; + wire[31:0] _vw_value; + wire _alu_is_zero; + STAGE2 stage2( + .vrw_value(_vrw_value), + .vw_value(_vw_value), + .ram_address(ram_address_stage2), + .alu_is_zero(_alu_is_zero), + .mblock_s2(mblock_s2), + .vr_source(vr_source), + .vr_value(vr_value), + .vrw_source(vrw_source), + .alu_op(mblock_alu_op), + .pc(pc), + .ram_value(ram_value)); // STAGE3 - // TODO: alu_op should be computed using instruction_op breakdowns. - wire[3:0] alu_op; - wire[31:0] v2; - - wire flag_alu_zero; - ALU alu( - .out(v2), - .is_zero(flag_alu_zero), - .op(alu_op), - .in0(v0), - .in1(v1)); - - // MBLOCK input only comes from ALU output. - assign mblock_input = v2; - - // TODO: jump instruction - PC_NEXT pc_next( - .program_counter_next(program_counter_next), - .program_counter(program_counter), - .is_powered_on(is_powered_on)); - - // @stage3 posedge following should freeze. - wire[15:0] program_counter_next; - flipflop16 pc( - .out(program_counter), - .in(program_counter_next), - .clk(clk3)); - + wire[31:0] vrw_value; + wire[31:0] vw_value; + wire alu_is_zero; + REGISTER_up_16b stage3_r0a( + .out(vrw_value[31:16]), + .in(_vrw_value[31:16]), + .clk(clk[3])); + REGISTER_up_16b stage3_r0b( + .out(vrw_value[15:0]), + .in(_vrw_value[15:0]), + .clk(clk[3])); + REGISTER_up_16b stage3_r1a( + .out(vw_value[31:16]), + .in(_vw_value[31:16]), + .clk(clk[3])); + REGISTER_up_16b stage3_r1b( + .out(vw_value[15:0]), + .in(_vw_value[15:0]), + .clk(clk[3])); + wire[14:0] unused0; + REGISTER_up_16b stage3_r2( + .out({unused0, alu_is_zero}), + .in({15'bzzzzzzzzzzzzzzz, _alu_is_zero}), + .clk(clk[3])); + + + wire execute_from_ram_new; + wire is_powered_on_new; + wire[15:0] pc_next; + + STAGE3 stage3( + .output_devices_value(output_devices_value), + .io_device_id(io_device_id_s3), + .ram_address(ram_address_stage3), + .ram_in(ram_in), + .ram_is_write(ram_is_write), + .output_is_write(output_is_write), + .pc_next(pc_next), + .execute_from_ram_new(execute_from_ram_new), + .is_powered_on_new(is_powered_on_new), + .mblock_s3(mblock_s3), + .vrw_value(vrw_value), + .vw_value(vw_value), + .vrw_source(vrw_source), + .pc(pc), + .is_powered_on(is_powered_on), + .flag_last_zero(flag_last_zero), + .execute_from_ram(flag_execute_from_ram), + .reset_button(reset_button)); + + wire[12:0] unused1; + REGISTER_down_16b stage3_r3( + .out({unused1, flag_last_zero, is_powered_on, flag_execute_from_ram}), + .in({13'bzzzzzzzzzzzzz, alu_is_zero, is_powered_on_new, execute_from_ram_new}), + .clk(clk[3])); + + REGISTER_down_16b stage3_r4( + .out(pc), + .in(pc_next), + .clk(clk[3])); + + // always @(negedge clk[0]) begin + // $display("Stage0: power=%b pc=%x ins=%b eram=%b", + // is_powered_on_new, pc, _instruction_binary, flag_execute_from_ram); + // end + // always @(negedge clk[1]) begin + // $display("Stage1: alu=%b s1=%b s2=%b s3=%b vrw_source=%x vr_source=%x", + // mblock_alu_op, mblock_s1, mblock_s2, mblock_s3, vrw_source, vr_source); + // end + // always @(negedge clk[2]) begin + // $display("Stage2: vr_value=%x", + // vr_value); + // end + // always @(negedge clk[3]) begin + // $display("Stage3: vrw_value=%x, vw_value=%x is_zero=%b", + // vrw_value, vw_value, alu_is_zero); + // end + // always @(posedge clk[0]) begin + // $display("StageE: power=%b, f_zero=%b, f_eram=%b pc=%x write_ram=%b wrire_io=%b", + // is_powered_on, flag_last_zero, flag_execute_from_ram, pc, ram_is_write, output_is_write); + // end endmodule \ No newline at end of file diff --git a/emulator/com/add_4.v b/emulator/com/add_4.v new file mode 100644 index 0000000..ee5470d --- /dev/null +++ b/emulator/com/add_4.v @@ -0,0 +1,6 @@ +module ADD_4_16b( + output[15:0] out, + input[15:0] in); + + assign out = in + 4; +endmodule diff --git a/emulator/com/add_4_test.v b/emulator/com/add_4_test.v new file mode 100644 index 0000000..9a00d4f --- /dev/null +++ b/emulator/com/add_4_test.v @@ -0,0 +1,20 @@ +`include "emulator/com/add_4.v" + +module adder_test; + reg[15:0] in; + wire[15:0] out; + + ADD_4_16b dut( + .out(out), + .in(in)); + + initial begin + in = 2536; + # 10 + $display("ADDER_TEST: in=%b out=%b", in, out); + if (out !== 2540) begin + $error("latch failed"); + $fatal(1); + end + end +endmodule diff --git a/emulator/com/alu.v b/emulator/com/alu.v new file mode 100644 index 0000000..760c132 --- /dev/null +++ b/emulator/com/alu.v @@ -0,0 +1,30 @@ +`define ALU_OP_ADD 4'b0000 + + +module ALU ( + output[31:0] out, + output is_zero, + input[3:0] op, + input[31:0] in_r, + input[31:0] in_rw); + + reg[31:0] mem; + + always @(op, in_r, in_rw) begin + case(op) + 4'b0000: mem = in_r+in_rw; + 4'b0001: mem = in_rw-in_r; + 4'b0010: mem = (in_rw<>in_r); + 4'b0100: mem = (in_r); + 4'b0101: mem = (in_rw); + 4'b0110: mem = (in_r&in_rw); + 4'b0111: mem = (in_r|in_rw); + 4'b1000: mem = (in_r^in_rw); + 4'b1001: mem = (((in_r&255)<<8)|in_rw&255); + endcase + end + assign out[31:0] = mem[31:0]; + assign is_zero = (mem == 0); + +endmodule diff --git a/emulator/com/alu_test.v b/emulator/com/alu_test.v new file mode 100644 index 0000000..5e2985a --- /dev/null +++ b/emulator/com/alu_test.v @@ -0,0 +1,128 @@ +`include "emulator/com/alu.v" + +module alu_test; + reg[31:0] in_r, in_rw; + reg[3:0] op; + wire[31:0] out; + wire is_zero; + + ALU dut( + .out(out), + .is_zero(is_zero), + .op(op), + .in_r(in_r), + .in_rw(in_rw)); + + initial begin + // ADD + op = 4'b0000; + in_r = 2536; + in_rw = 113; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 2649 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // SUB + op = 4'b0001; + in_r = 113; + in_rw = 2536; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 2423 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // LSR + op = 4'b0010; + in_r = 2; + in_rw = 2536; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 10144 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // RSR + op = 4'b0011; + in_r = 4; + in_rw = 2536; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 158 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // Fist Operand + op = 4'b0100; + in_r = 2536; + in_rw = 4; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 2536 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // Second Operand + op = 4'b0101; + in_r = 2536; + in_rw = 4; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 4 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // AND + op = 4'b0110; + in_r = 2536; + in_rw = 113; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 96 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // OR + op = 4'b0111; + in_r = 2536; + in_rw = 3113; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 3561 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // XOR + op = 4'b1000; + in_r = 2536; + in_rw = 3113; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 1473 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + // R_SHL8_RW_OR + op = 4'b01001; + in_r = 213; + in_rw = 123; + # 10 + $display("ALU_TEST: op=%b in_r=%b in_rw=%b", op, in_r, in_rw); + if (out !== 54651 || is_zero !== 0) begin + $error("alu failed"); + $fatal(1); + end + + end +endmodule diff --git a/emulator/com/decoder.v b/emulator/com/decoder.v new file mode 100644 index 0000000..2cca355 --- /dev/null +++ b/emulator/com/decoder.v @@ -0,0 +1,12 @@ +module DECODER_3( + output[7:0] out, + input[2:0] in); + assign out[0] = (in==0); + assign out[1] = (in==1); + assign out[2] = (in==2); + assign out[3] = (in==3); + assign out[4] = (in==4); + assign out[5] = (in==5); + assign out[6] = (in==6); + assign out[7] = (in==7); +endmodule diff --git a/emulator/com/decoder_test.v b/emulator/com/decoder_test.v new file mode 100644 index 0000000..809b617 --- /dev/null +++ b/emulator/com/decoder_test.v @@ -0,0 +1,30 @@ +`include "emulator/com/decoder.v" + +module decoder_3_test; + reg [2:0] in; + wire [7:0] out; + + DECODER_3 dut(.out(out), .in(in)); + + initial begin + in = 3'b010; + # 10 + $display("DECODER_TEST: in=%b out=%b", in, out); + if (out !== 8'b00000100) begin + $error("decoder failed"); + end + in = 3'b101; + # 10 + $display("DECODER_TEST: in=%b out=%b", in, out); + if (out !== 8'b00100000) begin + $error("decoder failed"); + end + in = 3'b111; + # 10 + $display("DECODER_TEST: in=%b out=%b", in, out); + if (out !== 8'b10000000) begin + $error("decoder failed"); + end + + end +endmodule diff --git a/emulator/com/mux.v b/emulator/com/mux.v new file mode 100644 index 0000000..88367b7 --- /dev/null +++ b/emulator/com/mux.v @@ -0,0 +1,32 @@ +`ifndef INCLUDED_MUX +`define INCLUDED_MUX + +module MUX_1_16b( + output reg [15:0] value, + input [15:0] A0, A1, + input S); + + always @(S, A0, A1) begin + if (S) begin + value = A1; + end else begin + value = A0; + end + end +endmodule + +module MUX_2_16b( + output reg [15:0] value, + input [15:0] A0, A1, A2, A3, + input [1:0] S); + + always @(S, A0, A1, A2, A3) begin + case (S) + 2'b00: value = A0; + 2'b01: value = A1; + 2'b10: value = A2; + 2'b11: value = A3; + endcase + end +endmodule +`endif \ No newline at end of file diff --git a/emulator/com/mux_test.v b/emulator/com/mux_test.v new file mode 100644 index 0000000..0dd72b4 --- /dev/null +++ b/emulator/com/mux_test.v @@ -0,0 +1,69 @@ +`include "emulator/com/mux.v" + +module mux_1_test; + reg[15:0] A0 = 16'b0110010101100101; + reg[15:0] A1 = 16'b1010110010101100; + reg S; + wire[15:0] out; + + MUX_1_16b dut(.value(out), .A0(A0), .A1(A1), .S(S)); + + initial begin + S = 0; + # 10 + $display("MUX_TEST: A0=%b A1=%b S=%b OUT=%b", A0, A1, S, out); + if (out !== A0) begin + $error("mux failed"); + $fatal(1); + end + S = 1; + # 10 + $display("MUX_TEST: A0=%b A1=%b S=%b OUT=%b", A0, A1, S, out); + if (out !== A1) begin + $error("mux failed"); + $fatal(1); + end + end +endmodule + +module mux_2_test; + reg[15:0] A0 = 16'b0110010101100101; + reg[15:0] A1 = 16'b1010110010101100; + reg[15:0] A2 = 16'b1010001001010101; + reg[15:0] A3 = 16'b0101010101010100; + reg[1:0] S; + wire[15:0] out; + + MUX_2_16b dut(.value(out), .A0(A0), .A1(A1), .A2(A2), .A3(A3), .S(S)); + + initial begin + S = 2'b00; + # 10 + $display("MUX_TEST: A0=%b A1=%b A1=%b A1=%b S=%b OUT=%b", A0, A1, S, out); + if (out !== A0) begin + $error("mux failed"); + $fatal(1); + end + S = 2'b01; + # 10 + $display("MUX_TEST: A0=%b A1=%b S=%b OUT=%b", A0, A1, S, out); + if (out !== A1) begin + $error("mux failed"); + $fatal(1); + end + S = 2'b10; + # 10 + $display("MUX_TEST: A0=%b A1=%b S=%b OUT=%b", A0, A1, S, out); + if (out !== A2) begin + $error("mux failed"); + $fatal(1); + end + S = 2'b11; + # 10 + $display("MUX_TEST: A0=%b A1=%b S=%b OUT=%b", A0, A1, S, out); + if (out !== A3) begin + $error("mux failed"); + $fatal(1); + end + end +endmodule diff --git a/emulator/com/rom.v b/emulator/com/rom.v new file mode 100644 index 0000000..f95ae4f --- /dev/null +++ b/emulator/com/rom.v @@ -0,0 +1,44 @@ +`ifndef INCLUDED_ROM +`define INCLUDED_ROM + +module _ROM_32bit_16aline( + output[31:0] out, + input[15:0] address); + parameter filename = "/dev/null"; + + reg[7:0] buffer[0:1024]; + initial begin + $readmemb(filename, buffer); + $display("ROM: %h", buffer[0]); + end + + assign out[7:0] = buffer[address+0]; + assign out[15:8] = buffer[address+1]; + assign out[23:16] = buffer[address+2]; + assign out[31:24] = buffer[address+3]; + +endmodule + +module ROM_BOOT( + output[31:0] out, + input[15:0] address); + parameter filename = "emulator/com/rom_boot.bin"; + reg[15:0] eaddress; + always @(address) begin + eaddress = address - 'h40; + end + _ROM_32bit_16aline #(.filename(filename)) + _rom(.out(out), + .address(eaddress)); +endmodule + +module ROM_PINGPONG( + output[31:0] out, + input[15:0] address); + parameter filename = "output/programs/ping_pong.bin"; + _ROM_32bit_16aline #(.filename(filename)) + _rom(.out(out), + .address(address)); +endmodule + +`endif \ No newline at end of file diff --git a/emulator/com/rom_boot.bin b/emulator/com/rom_boot.bin new file mode 100644 index 0000000..4260dcb --- /dev/null +++ b/emulator/com/rom_boot.bin @@ -0,0 +1,18 @@ +01000100 00000000 00000000 00000000 +00110100 00000010 00000000 00000000 +00000100 00000100 00000010 00000000 +00100100 00000010 00000000 00000010 +00110011 00000010 00000000 00000010 +00110100 00000010 00000100 00000100 +00110100 00000010 00001000 10000000 +00000100 00000100 00000010 00000100 +00100100 00000010 00001100 00000010 +00000100 00000110 00001000 00001100 +00110000 00000010 00001000 00000100 +00110000 00000010 00000100 00000100 +00110001 00000010 00000000 00000001 +10110101 00001101 01011100 00000000 +00110100 00000010 00100000 00000011 +00110010 00000010 00100000 00001000 +00110111 00000010 00100000 11111100 +10110101 00001001 10000000 00000000 diff --git a/emulator/com/rom_test.bin b/emulator/com/rom_test.bin new file mode 100644 index 0000000..23296fd --- /dev/null +++ b/emulator/com/rom_test.bin @@ -0,0 +1,10 @@ +10000010 10111111 01111000 01010111 +11111100 10101100 11010000 10101001 +00000001 00110110 11111101 10011101 +11111010 11111111 01000001 11111110 +00010110 01000110 00110111 00001001 +00111110 10011101 10001011 10111011 +10000011 10111010 00111000 00011000 +10011111 01111010 10000010 00101001 +00110101 00100101 10000001 00011101 +01110000 10111000 00001001 00011101 diff --git a/emulator/com/rom_test.v b/emulator/com/rom_test.v new file mode 100644 index 0000000..f9a8f7c --- /dev/null +++ b/emulator/com/rom_test.v @@ -0,0 +1,45 @@ +`include "emulator/com/rom.v" + +module rom_test; + reg[15:0] address; + wire[31:0] out; + + _ROM_32bit_16aline #(.filename("emulator/com/rom_test.bin")) + dut(.out(out), + .address(address)); + + initial begin + address = 0; + # 10 + $display("ROM_TEST: address=%b out=%b", address, out); + if (out !== 32'b01010111011110001011111110000010) begin + $error("rom failed"); + $fatal(1); + end + address = 3*4; + # 10 + $display("ROM_TEST: address=%b out=%b", address, out); + if (out !== 32'b11111110010000011111111111111010) begin + $error("rom failed"); + $fatal(1); + end + end +endmodule + +module rom_boot_test; + reg[15:0] address; + wire[31:0] out; + + ROM_BOOT dut(.out(out), + .address(address)); + + initial begin + address = 'h40; + # 10 + $display("BROM_TEST: address=%b out=%b", address, out); + if (out !== 32'b00000000000000000000000001000100) begin + $error("rom failed"); + $fatal(1); + end + end +endmodule diff --git a/emulator/com/stage0.v b/emulator/com/stage0.v new file mode 100644 index 0000000..986c0fd --- /dev/null +++ b/emulator/com/stage0.v @@ -0,0 +1,26 @@ +`include "emulator/com/mux.v" + +module STAGE0( + output[31:0] instruction_binary, + output[15:0] ram_address, + output[15:0] brom_address, + input [31:0] ram_value, + input [31:0] brom_value, + input [15:0] pc, + input execute_from_ram); + + assign ram_address = pc; + assign brom_address = pc; + + MUX_1_16b insh( + .value(instruction_binary[31:16]), + .A0(brom_value[31:16]), + .A1(ram_value[31:16]), + .S(execute_from_ram)); + MUX_1_16b insl( + .value(instruction_binary[15:0]), + .A0(brom_value[15:0]), + .A1(ram_value[15:0]), + .S(execute_from_ram)); + +endmodule diff --git a/emulator/com/stage0_test.v b/emulator/com/stage0_test.v new file mode 100644 index 0000000..47a8401 --- /dev/null +++ b/emulator/com/stage0_test.v @@ -0,0 +1,64 @@ +`include "emulator/com/stage0.v" +`include "emulator/seq/ram.v" +`include "emulator/com/rom.v" + +module stage0_test; + wire[15:0] rom_address; + wire[31:0] rom_value; + ROM_BOOT dut1(.out(rom_value), .address(rom_address)); + + reg clk; + reg ram_is_write; + wire[15:0] ram_address; + reg[31:0] ram_in; + wire[31:0] ram_value; + RAM_32bit_16aline dut2( + .out(ram_value), + .in(ram_in), + .address(ram_address), + .is_write(ram_is_write), + .clk(clk)); + + wire[31:0] instruction_binary; + reg[15:0] pc; + reg execute_from_ram; + + STAGE0 dut( + .instruction_binary(instruction_binary), + .ram_address(ram_address), + .brom_address(rom_address), + .ram_value(ram_value), + .brom_value(rom_value), + .pc(pc), + .execute_from_ram(execute_from_ram)); + + localparam [31:0] INPUT1 = 32'b11100101111110000100101010110001; + + initial begin + pc = 16'b0000000001000100; // 0x44 + ram_is_write = 1; + ram_in = INPUT1; + clk = 1; + # 10 + clk = 0; + # 10 + execute_from_ram = 0; + # 10 + $display("STAGE0_TEST: pc=%b out=%b rom_address=%b rom_value=%b", pc, instruction_binary, rom_address, rom_value); + if (instruction_binary !== 32'b00000000000000000000001000110100) begin + $error("stage0 failed"); + $fatal(1); + end + # 10 + execute_from_ram = 1; + # 10 + $display("STAGE0_TEST: pc=%b out=%b", pc, instruction_binary); + if (instruction_binary !== INPUT1) begin + $error("stage0 failed"); + $fatal(1); + end + + end + + +endmodule diff --git a/emulator/com/stage1.v b/emulator/com/stage1.v new file mode 100644 index 0000000..85ac145 --- /dev/null +++ b/emulator/com/stage1.v @@ -0,0 +1,36 @@ +`include "emulator/com/mux.v" + +module STAGE1( + output[31:0] vr_value, + output[7:0] io_device_id, + output[15:0] ram_address, + input[1:0] mblock_s1, + input[7:0] vr_source, + input[31:0] input_devices_value, + input[31:0] ram_value); + + wire[31:0] _const_value; + + assign io_device_id = vr_source; + assign _const_value[7:0] = vr_source; + assign _const_value[31:8] = 24'b000000000000000000000000; + assign ram_address[7:0] = vr_source; + assign ram_address[15:8] = 8'b00000000; + + MUX_2_16b m1( + .value(vr_value[31:16]), + .A0(ram_value[31:16]), + .A1(16'bxxxxxxxxxxxxxxxx), + .A2(input_devices_value[31:16]), + .A3(_const_value[31:16]), + .S(mblock_s1)); + + MUX_2_16b m2( + .value(vr_value[15:0]), + .A0(ram_value[15:0]), + .A1(16'bxxxxxxxxxxxxxxxx), + .A2(input_devices_value[15:0]), + .A3(_const_value[15:0]), + .S(mblock_s1)); + +endmodule diff --git a/emulator/com/stage1_test.v b/emulator/com/stage1_test.v new file mode 100644 index 0000000..72e183c --- /dev/null +++ b/emulator/com/stage1_test.v @@ -0,0 +1,54 @@ +`include "emulator/com/stage1.v" + +module stage1_test; + wire[31:0] vr_value; + wire[7:0] io_device_id; + wire[15:0] ram_address; + + reg[1:0] mblock_s1; + reg[7:0] vr_source; + reg[31:0] input_devices_value; + reg[31:0] ram_value; + + STAGE1 dut( + .vr_value(vr_value), + .io_device_id(io_device_id), + .ram_address(ram_address), + .mblock_s1(mblock_s1), + .vr_source(vr_source), + .input_devices_value(input_devices_value), + .ram_value(ram_value)); + + initial begin + ram_value = 55; + input_devices_value = 22; + vr_source = 33; + # 10 + mblock_s1 = 0; + # 10 + $display("STAGE1_TEST: vr_value=%b ram_address=%b", vr_value, ram_address); + if (vr_value !== 55 || ram_address !== 33) begin + $error("stage1 failed"); + $fatal(1); + end + # 10 + mblock_s1 = 2; + # 10 + $display("STAGE1_TEST: vr_value=%b io_device_id=%b", vr_value, io_device_id); + if (vr_value !== 22 || io_device_id !== 33) begin + $error("stage1 failed"); + $fatal(1); + end + # 10 + mblock_s1 = 3; + # 10 + $display("STAGE1_TEST: vr_value=%b const=%b", vr_value, vr_source); + if (vr_value !== 33) begin + $error("stage1 failed"); + $fatal(1); + end + + end + + +endmodule diff --git a/emulator/com/stage2.v b/emulator/com/stage2.v new file mode 100644 index 0000000..2c4d772 --- /dev/null +++ b/emulator/com/stage2.v @@ -0,0 +1,63 @@ +`include "emulator/com/mux.v" +`include "emulator/com/alu.v" + +module STAGE2( + output[31:0] vrw_value, + output[31:0] vw_value, + output[15:0] ram_address, + output alu_is_zero, + input[2:0] mblock_s2, + input[7:0] vr_source, + input[31:0] vr_value, + input[7:0] vrw_source, + input[3:0] alu_op, + input[15:0] pc, + input[31:0] ram_value); + + wire[15:0] _iv; + wire[31:0] _m_vrw_value; + + MUX_2_16b m1( + .value(_iv[15:0]), + .A0({8'b00000000, vrw_source[7:0]}), + .A1(vr_value[15:0]), + .A2({vr_source[7:0], vrw_source[7:0]}), + .A3(16'bxxxxxxxxxxxxxxxx), + .S(mblock_s2[1:0])); + + assign ram_address = _iv; + + MUX_1_16b m2a( + .value(_m_vrw_value[31:16]), + .A0(ram_value[31:16]), + .A1(16'b0000000000000000), + .S(mblock_s2[2])); + MUX_1_16b m2b( + .value(_m_vrw_value[15:0]), + .A0(ram_value[15:0]), + .A1(_iv[15:0]), + .S(mblock_s2[2])); + + wire want_pc = ( + mblock_s2[0] & mblock_s2[1] & mblock_s2[2] + ); + + MUX_1_16b m3a( + .value(vrw_value[31:16]), + .A0(_m_vrw_value[31:16]), + .A1(16'b0000000000000000), + .S(want_pc)); + MUX_1_16b m3b( + .value(vrw_value[15:0]), + .A0(_m_vrw_value[15:0]), + .A1(pc[15:0]), + .S(want_pc)); + + ALU alu( + .out(vw_value), + .is_zero(alu_is_zero), + .op(alu_op), + .in_r(vr_value), + .in_rw(vrw_value)); + +endmodule diff --git a/emulator/com/stage2_test.v b/emulator/com/stage2_test.v new file mode 100644 index 0000000..d4acc4f --- /dev/null +++ b/emulator/com/stage2_test.v @@ -0,0 +1,98 @@ +`include "emulator/com/stage2.v" + +module stage2_test; + wire[31:0] vrw_value; + wire[31:0] vw_value; + wire[15:0] ram_address; + wire alu_is_zero; + + reg[2:0] mblock_s2; + reg[7:0] vr_source; + reg[31:0] vr_value; + reg[7:0] vrw_source; + reg[3:0] alu_op; + reg[15:0] pc; + reg[31:0] ram_value; + + STAGE2 dut( + .vrw_value(vrw_value), + .vw_value(vw_value), + .ram_address(ram_address), + .alu_is_zero(alu_is_zero), + .mblock_s2(mblock_s2), + .vr_source(vr_source), + .vr_value(vr_value), + .vrw_source(vrw_source), + .alu_op(alu_op), + .pc(pc), + .ram_value(ram_value)); + + initial begin + vr_source = 10; + vr_value = 1000; + vrw_source = 20; + alu_op = 0; // add + pc = 84; + ram_value = 99; + # 10 + mblock_s2 = 0; + # 10 + $display("STAGE2_TEST: vrw_value=%b vw_value=%b alu_is_zero=%b ram_address=%b", vrw_value, vw_value, alu_is_zero, ram_address); + if (vrw_value !== 99 || ram_address !== 20 || vw_value !== 1099 || alu_is_zero !== 0) begin + $error("stage2 failed"); + $fatal(1); + end + # 10 + mblock_s2 = 1; + # 10 + $display("STAGE2_TEST: vrw_value=%b vw_value=%b alu_is_zero=%b ram_address=%b", vrw_value, vw_value, alu_is_zero, ram_address); + if (vrw_value !== 99 || ram_address !== 1000 || vw_value !== 1099 || alu_is_zero !== 0) begin + $error("stage2 failed"); + $fatal(1); + end + # 10 + mblock_s2 = 2; + # 10 + $display("STAGE2_TEST: vrw_value=%b vw_value=%b alu_is_zero=%b ram_address=%b", vrw_value, vw_value, alu_is_zero, ram_address); + if (vrw_value !== 99 || ram_address !== ((10<<8)|20) || vw_value !== 1099 || alu_is_zero !== 0) begin + $error("stage2 failed"); + $fatal(1); + end + # 10 + mblock_s2 = 4; + # 10 + $display("STAGE2_TEST: vrw_value=%b vw_value=%b alu_is_zero=%b", vrw_value, vw_value, alu_is_zero); + if (vrw_value !== 20 || vw_value !== 1020 || alu_is_zero !== 0) begin + $error("stage2 failed"); + $fatal(1); + end + # 10 + mblock_s2 = 6; + # 10 + $display("STAGE2_TEST: vrw_value=%b vw_value=%b alu_is_zero=%b ram_address=%b", vrw_value, vw_value, alu_is_zero, ram_address); + if (vrw_value !== ((10<<8)|20) || vw_value !== (((10<<8)|20)+1000) || alu_is_zero !== 0) begin + $error("stage2 failed"); + $fatal(1); + end + # 10 + mblock_s2 = 7; + # 10 + $display("STAGE2_TEST: vrw_value=%b vw_value=%b alu_is_zero=%b ram_address=%b", vrw_value, vw_value, alu_is_zero, ram_address); + if (vrw_value !== 84 || vw_value !== 1084 || alu_is_zero !== 0) begin + $error("stage2 failed"); + $fatal(1); + end + # 10 + mblock_s2 = 0; + alu_op = 1; // sub + ram_value = 1000; + # 10 + $display("STAGE2_TEST: vrw_value=%b vw_value=%b alu_is_zero=%b ram_address=%b", vrw_value, vw_value, alu_is_zero, ram_address); + if (vrw_value !== 1000 || ram_address !== 20 || vw_value !== 0 || alu_is_zero !== 1) begin + $error("stage2 failed"); + $fatal(1); + end + end + + +endmodule diff --git a/emulator/com/stage3.v b/emulator/com/stage3.v new file mode 100644 index 0000000..79bf853 --- /dev/null +++ b/emulator/com/stage3.v @@ -0,0 +1,63 @@ +`include "emulator/com/mux.v" +`include "emulator/com/add_4.v" +`include "emulator/com/decoder.v" + +`define BOOTSEQUENCE_ORG 16'b0000000001000100 + +module STAGE3( + output[31:0] output_devices_value, + output[7:0] io_device_id, + output[15:0] ram_address, + output[31:0] ram_in, + output ram_is_write, + output output_is_write, + output[15:0] pc_next, + output execute_from_ram_new, + output is_powered_on_new, + input[2:0] mblock_s3, + input[31:0] vrw_value, + input[31:0] vw_value, + input[7:0] vrw_source, + input[15:0] pc, + input is_powered_on, + input flag_last_zero, + input execute_from_ram, + input reset_button); + + wire[7:0] mblock_s3d; + DECODER_3 dut(.out(mblock_s3d), .in(mblock_s3)); + + assign output_devices_value = vw_value; + assign io_device_id = vrw_source; + + assign ram_in = vw_value; + MUX_1_16b m1( + .value(ram_address[15:0]), + .A0(vrw_value[15:0]), + .A1({8'b00000000, vrw_source[7:0]}), + .S(mblock_s3d[1])); + or(ram_is_write, mblock_s3d[1], mblock_s3d[3]); + assign output_is_write = mblock_s3d[2]; + + wire is_jump = (mblock_s3d[4] | + (mblock_s3d[5] & flag_last_zero) | + (mblock_s3d[6] & (!flag_last_zero))); + wire[15:0] pc_4; + ADD_4_16b add4( + .out(pc_4), + .in(pc)); + wire[15:0] _pc_next; + MUX_1_16b m2( + .value(_pc_next), + .A0(pc_4), + .A1(vw_value[15:0]), + .S(is_jump)); + MUX_1_16b m3( + .value(pc_next), + .A0(_pc_next), + .A1(`BOOTSEQUENCE_ORG), + .S(reset_button)); + + assign is_powered_on_new = (is_powered_on & (!mblock_s3d[7])) | reset_button; + assign execute_from_ram_new = (execute_from_ram | mblock_s3d[4]) & (!reset_button); +endmodule diff --git a/emulator/com/stage3_test.v b/emulator/com/stage3_test.v new file mode 100644 index 0000000..0fab75e --- /dev/null +++ b/emulator/com/stage3_test.v @@ -0,0 +1,149 @@ +`include "emulator/com/stage3.v" + +module stage3_test; + wire[31:0] output_devices_value; + wire[7:0] io_device_id; + wire[15:0] ram_address; + wire[31:0] ram_in; + wire ram_is_write; + wire output_is_write; + wire[15:0] pc_next; + wire execute_from_ram_new; + wire is_powered_on_new; + + reg[2:0] mblock_s3; + reg[31:0] vrw_value; + reg[31:0] vw_value; + reg[7:0] vrw_source; + reg[15:0] pc; + reg is_powered_on; + reg flag_last_zero; + reg execute_from_ram; + reg reset_button; + + STAGE3 dut( + .output_devices_value(output_devices_value), + .io_device_id(io_device_id), + .ram_address(ram_address), + .ram_in(ram_in), + .ram_is_write(ram_is_write), + .output_is_write(output_is_write), + .pc_next(pc_next), + .execute_from_ram_new(execute_from_ram_new), + .is_powered_on_new(is_powered_on_new), + .mblock_s3(mblock_s3), + .vrw_value(vrw_value), + .vw_value(vw_value), + .vrw_source(vrw_source), + .pc(pc), + .is_powered_on(is_powered_on), + .flag_last_zero(flag_last_zero), + .execute_from_ram(execute_from_ram), + .reset_button(reset_button)); + + initial begin + reset_button = 0; + is_powered_on = 1; + execute_from_ram = 1; + pc = 10; + flag_last_zero = 0; + mblock_s3 = 0; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b radd=%b rin=%b", mblock_s3, pc_next, ram_is_write, output_is_write, ram_address, ram_in); + if (pc_next!==14 || ram_is_write!==0 || output_is_write!==0) begin + $error("stage3 failed"); + $fatal(1); + end + + mblock_s3 = 1; + vw_value = 99; + vrw_source = 15; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b radd=%b rin=%b", mblock_s3, pc_next, ram_is_write, output_is_write, ram_address, ram_in); + if (pc_next!==14 || ram_address!==15 || ram_in!==99 || ram_is_write!==1 || output_is_write!==0) begin + $error("stage3 failed"); + $fatal(1); + end + + mblock_s3 = 2; + vw_value = 99; + vrw_source = 15; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b radd=%b rin=%b", mblock_s3, pc_next, ram_is_write, output_is_write, ram_address, ram_in); + if (pc_next!==14 || io_device_id!==15 || output_devices_value!==99 || ram_is_write!==0 || output_is_write!==1) begin + $error("stage3 failed"); + $fatal(1); + end + + mblock_s3 = 3; + vw_value = 99; + vrw_value = 97; + vrw_source = 15; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b radd=%b rin=%b", mblock_s3, pc_next, ram_is_write, output_is_write, ram_address, ram_in); + if (pc_next!==14 || ram_address!==97 || ram_in!==99 || ram_is_write!==1 || output_is_write!==0) begin + $error("stage3 failed"); + $fatal(1); + end + + mblock_s3 = 4; + vw_value = 99; + flag_last_zero = 0; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b", mblock_s3, pc_next, ram_is_write, output_is_write); + if (pc_next!==99 || ram_is_write!==0 || output_is_write!==0) begin + $error("stage3 failed"); + $fatal(1); + end + + mblock_s3 = 5; + flag_last_zero = 1; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b", mblock_s3, pc_next, ram_is_write, output_is_write); + if (pc_next!==99 || ram_is_write!==0 || output_is_write!==0) begin + $error("stage3 failed"); + $fatal(1); + end + flag_last_zero = 0; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b", mblock_s3, pc_next, ram_is_write, output_is_write); + if (pc_next!==14 || ram_is_write!==0 || output_is_write!==0) begin + $error("stage3 failed"); + $fatal(1); + end + + mblock_s3 = 6; + flag_last_zero = 0; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b", mblock_s3, pc_next, ram_is_write, output_is_write); + if (pc_next!==99 || ram_is_write!==0 || output_is_write!==0) begin + $error("stage3 failed"); + $fatal(1); + end + flag_last_zero = 1; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b write_ram=%b write_out=%b", mblock_s3, pc_next, ram_is_write, output_is_write); + if (pc_next!==14 || ram_is_write!==0 || output_is_write!==0) begin + $error("stage3 failed"); + $fatal(1); + end + + mblock_s3 = 7; + # 10 + $display("STAGE3_TEST: mblock_s3=%b", mblock_s3); + if (is_powered_on_new !== 0 || execute_from_ram_new !== 1) begin + $error("stage3 failed"); + $fatal(1); + end + + mblock_s3 = 0; + reset_button = 1; + is_powered_on = 0; + # 10 + $display("STAGE3_TEST: mblock_s3=%b pc_next=%b", mblock_s3, pc_next); + if (pc_next !== 'h44 || is_powered_on_new !== 1 || execute_from_ram_new !== 0) begin + $error("stage3 failed"); + $fatal(1); + end + end +endmodule diff --git a/emulator/executable_chipset.v b/emulator/executable_chipset.v new file mode 100644 index 0000000..522751e --- /dev/null +++ b/emulator/executable_chipset.v @@ -0,0 +1,27 @@ +`include "emulator/chipset.v" + +module chipset_test; + reg reset_button; + + wire is_powered_on; + wire flag_execute_from_ram; + wire[15:0] pc; + CHIPSET dut( + .reset_button(reset_button), + .pc(pc), + .is_powered_on(is_powered_on), + .flag_execute_from_ram(flag_execute_from_ram)); + + initial begin + reset_button = 0; + # 80 + reset_button = 1; + # 80 + reset_button = 0; + # 200000 + if (reset_button !== 0) begin + $error("chipset failed"); + $fatal(1); + end + end +endmodule diff --git a/emulator/lib/adder.v b/emulator/lib/adder.v deleted file mode 100644 index f1502ba..0000000 --- a/emulator/lib/adder.v +++ /dev/null @@ -1,7 +0,0 @@ -module ADDER( - output[15:0] out, - input[15:0] in0, - input[15:0] in1); - - assign out = in0+in1; -endmodule diff --git a/emulator/lib/adder_test.v b/emulator/lib/adder_test.v deleted file mode 100644 index 269d87c..0000000 --- a/emulator/lib/adder_test.v +++ /dev/null @@ -1,22 +0,0 @@ -`include "emulator/lib/adder.v" - -module adder_test; - reg[15:0] in0, in1; - wire[15:0] out; - - ADDER dut( - .out(out), - .in0(in0), - .in1(in1)); - - initial begin - in0 = 2536; - in1 = 113; - # 10 - $display("ADDER_TEST: in0=%b in1=%b", in0, in1); - if (out !== 2649) begin - $error("latch failed"); - $fatal(1); - end - end -endmodule diff --git a/emulator/lib/alu.v b/emulator/lib/alu.v deleted file mode 100644 index 782ceb8..0000000 --- a/emulator/lib/alu.v +++ /dev/null @@ -1,25 +0,0 @@ -module ALU ( - output[31:0] out, - output is_zero, - input[2:0] op, - input[31:0] in0, - input[31:0] in1); - - reg[31:0] mem; - - always @(op, in0, in1) begin - case(op) - 3'b000: mem <= in0+in1; - 3'b001: mem <= in0-in1; - 3'b010: mem <= (in0<>in1); - 3'b100: mem <= (in0); - 3'b101: mem <= (in0&in1); - 3'b110: mem <= (in0|in1); - - endcase - end - assign out[31:0] = mem[31:0]; - assign is_zero = (mem == 0); - -endmodule diff --git a/emulator/lib/alu_test.v b/emulator/lib/alu_test.v deleted file mode 100644 index 7e34a65..0000000 --- a/emulator/lib/alu_test.v +++ /dev/null @@ -1,106 +0,0 @@ -`include "emulator/lib/alu.v" - -module alu_test; - reg[31:0] in0, in1; - reg[2:0] op; - wire[31:0] out; - wire is_zero; - - ALU dut( - .out(out), - .is_zero(is_zero), - .op(op), - .in0(in0), - .in1(in1)); - - initial begin - // ADD - op = 3'b000; - in0 = 2536; - in1 = 113; - # 10 - $display("ALU_TEST: op=%b in0=%b in1=%b", op, in0, in1); - if (out !== 2649 || is_zero !== 0) begin - $error("alu failed"); - $fatal(1); - end - - // SUB - op = 3'b001; - in0 = 2536; - in1 = 113; - # 10 - $display("ALU_TEST: op=%b in0=%b in1=%b", op, in0, in1); - if (out !== 2423 || is_zero !== 0) begin - $error("alu failed"); - $fatal(1); - end - - // LSR - op = 3'b010; - in0 = 2536; - in1 = 2; - # 10 - $display("ALU_TEST: op=%b in0=%b in1=%b", op, in0, in1); - if (out !== 10144 || is_zero !== 0) begin - $error("alu failed"); - $fatal(1); - end - - // RSR - op = 3'b011; - in0 = 2536; - in1 = 4; - # 10 - $display("ALU_TEST: op=%b in0=%b in1=%b", op, in0, in1); - if (out !== 158 || is_zero !== 0) begin - $error("alu failed"); - $fatal(1); - end - - // Fist Operand - op = 3'b100; - in0 = 2536; - in1 = 4; - # 10 - $display("ALU_TEST: op=%b in0=%b in1=%b", op, in0, in1); - if (out !== 2536 || is_zero !== 0) begin - $error("alu failed"); - $fatal(1); - end - - // CMP as alias of SUB - op = 3'b001; - in0 = 2536; - in1 = 2536; - # 10 - $display("ALU_TEST: op=%b in0=%b in1=%b", op, in0, in1); - if (out !== 0 || is_zero !== 1) begin - $error("alu failed"); - $fatal(1); - end - - // AND - op = 3'b101; - in0 = 2536; - in1 = 113; - # 10 - $display("ALU_TEST: op=%b in0=%b in1=%b", op, in0, in1); - if (out !== 96 || is_zero !== 0) begin - $error("alu failed"); - $fatal(1); - end - - // OR - op = 3'b110; - in0 = 2536; - in1 = 3113; - # 10 - $display("ALU_TEST: op=%b in0=%b in1=%b", op, in0, in1); - if (out !== 3561 || is_zero !== 0) begin - $error("alu failed"); - $fatal(1); - end - - end -endmodule diff --git a/emulator/lib/decoder.v b/emulator/lib/decoder.v deleted file mode 100644 index b01db42..0000000 --- a/emulator/lib/decoder.v +++ /dev/null @@ -1,22 +0,0 @@ -module DECODER_4_2( - output[3:0] out, - input[1:0] in); - - assign out[0] = (~in[1] & ~in[0]); - assign out[1] = (~in[1] & in[0]); - assign out[2] = ( in[1] & ~in[0]); - assign out[3] = ( in[1] & in[0]); -endmodule - - -module DECODER_8_3( - output[7:0] out, - input[2:0] in); - - wire [3:0] _out; - DECODER_4_2 d(_out[3:0], in[1:0]); - - wire not_in2 = ~in[2]; - assign out[3:0] = _out[3:0] & {not_in2, not_in2, not_in2, not_in2}; - assign out[7:4] = _out[3:0] & {in[2], in[2], in[2], in[2]}; -endmodule diff --git a/emulator/lib/decoder_test.v b/emulator/lib/decoder_test.v deleted file mode 100644 index eca58cb..0000000 --- a/emulator/lib/decoder_test.v +++ /dev/null @@ -1,61 +0,0 @@ -`include "emulator/lib/decoder.v" - -module decoder_4_2_test; - reg [1:0] in; - wire [3:0] out; - - DECODER_4_2 dut(.out(out), .in(in)); - - initial begin - in = 2'b00; - # 10 - $display("DECODER_TEST: in=%b out=%b", in, out); - if (out != 4'b0001) begin - $error("decoder failed"); - end - in = 2'b01; - # 10 - $display("DECODER_TEST: in=%b out=%b", in, out); - if (out != 4'b0010) begin - $error("decoder failed"); - end - in = 2'b10; - # 10 - $display("DECODER_TEST: in=%b out=%b", in, out); - if (out != 4'b0100) begin - $error("decoder failed"); - end - in = 2'b11; - # 10 - $display("DECODER_TEST: in=%b out=%b", in, out); - if (out != 4'b1000) begin - $error("decoder failed"); - end - - end -endmodule - - -module decoder_8_3_test; - reg [2:0] in; - wire [7:0] out; - - DECODER_8_3 dut(.out(out), .in(in)); - - initial begin - in = 3'b010; - # 10 - $display("DECODER_TEST: in=%b out=%b", in, out); - if (out != 8'b00000100) begin - $error("decoder failed"); - $fatal(1); - end - in = 3'b101; - # 10 - $display("DECODER_TEST: in=%b out=%b", in, out); - if (out != 8'b00100000) begin - $error("decoder failed"); - $fatal(1); - end - end -endmodule diff --git a/emulator/lib/flipflop.v b/emulator/lib/flipflop.v deleted file mode 100644 index e311b20..0000000 --- a/emulator/lib/flipflop.v +++ /dev/null @@ -1,30 +0,0 @@ -module __flipflop #(parameter BITS = 32)( - output[BITS-1:0] out, - input clk, - input[BITS-1:0] in); - - reg[BITS-1:0] mem; - always @(posedge clk) begin - mem[BITS-1:0] <= in[BITS-1:0]; - end - assign out[BITS-1:0] = mem[BITS-1:0]; -endmodule - -module flipflop32( - output[31:0] out, - input clk, - input[31:0] in); - - __flipflop #(.BITS(32)) ff(.out(out), .clk(clk), .in(in)); - -endmodule - -module flipflop16( - output[15:0] out, - input clk, - input[15:0] in); - - __flipflop #(.BITS(16)) ff(.out(out), .clk(clk), .in(in)); - -endmodule - diff --git a/emulator/lib/flipflop_test.v b/emulator/lib/flipflop_test.v deleted file mode 100644 index 9c93434..0000000 --- a/emulator/lib/flipflop_test.v +++ /dev/null @@ -1,58 +0,0 @@ -`include "emulator/lib/flipflop.v" - -module flipflop_test; - reg[31:0] in; - reg clk; - wire[31:0] out; - - flipflop32 dut(.out(out), .in(in), .clk(clk)); - - initial begin - clk = 0; - in = 32'b00110110110101010100101101101000; - # 10 - clk = 1; - # 10 - $display("FLIPFLOP: in=%b out=%b clk=%b", in, out, clk); - if (out !== 32'b00110110110101010100101101101000) begin - $error("flipflop failed"); - $fatal(1); - end - - clk = 0; - # 10 - in = 32'b01100011111101011011010100000100; - # 10 - $display("FLIPFLOP: in=%b out=%b clk=%b", in, out, clk); - if (out !== 32'b00110110110101010100101101101000) begin - $error("flipflop failed"); - $fatal(1); - end - - in = 32'b10101100011011010010001010011001; - # 10 - $display("FLIPFLOP: in=%b out=%b clk=%b", in, out, clk); - if (out !== 32'b00110110110101010100101101101000) begin - $error("flipflop failed"); - $fatal(1); - end - - clk = 1; - # 10 - $display("FLIPFLOP: in=%b out=%b clk=%b", in, out, clk); - if (out !== 32'b10101100011011010010001010011001) begin - $error("flipflop failed"); - $fatal(1); - end - - clk = 0; - # 10 - in = 32'b10101011001010001101001000011011; - # 10 - $display("FLIPFLOP: in=%b out=%b clk=%b", in, out, clk); - if (out !== 32'b10101100011011010010001010011001) begin - $error("flipflop failed"); - $fatal(1); - end - end -endmodule diff --git a/emulator/lib/latch.v b/emulator/lib/latch.v deleted file mode 100644 index 0479815..0000000 --- a/emulator/lib/latch.v +++ /dev/null @@ -1,13 +0,0 @@ -module latch_d(output out, input in, input enable); - // we want latch to always be on and returing - // while write when d is active. - - reg mem; - - always @(in, enable) begin - if (enable) begin - mem <= in; - end - end - assign out = mem; -endmodule diff --git a/emulator/lib/latch_test.v b/emulator/lib/latch_test.v deleted file mode 100644 index c9fb2e1..0000000 --- a/emulator/lib/latch_test.v +++ /dev/null @@ -1,73 +0,0 @@ -`include "emulator/lib/latch.v" - -module latch_d_test; - reg I, ENABLE; - wire O; - - latch_d dut(.out(O), .in(I), .enable(ENABLE)); - - initial begin - I = 0; - ENABLE = 1; - # 10 - $display("LATCH_TEST: I=%b O=%b ENABLE=%b", I, O, ENABLE); - if (O !== 0) begin - $error("latch failed"); - $fatal(1); - end - - I = 1; - ENABLE = 1; - # 10 - $display("LATCH_TEST: I=%b O=%b ENABLE=%b", I, O, ENABLE); - if (O !== 1) begin - $error("latch failed"); - $fatal(1); - end - - I = 1; - ENABLE = 0; - # 10 - $display("LATCH_TEST: I=%b O=%b ENABLE=%b", I, O, ENABLE); - if (O !== 1) begin - $error("latch failed"); - $fatal(1); - end - - I = 0; - ENABLE = 0; - # 10 - $display("LATCH_TEST: I=%b O=%b ENABLE=%b", I, O, ENABLE); - if (O !== 1) begin - $error("latch failed"); - $fatal(1); - end - - I = 1; - ENABLE = 0; - # 10 - $display("LATCH_TEST: I=%b O=%b ENABLE=%b", I, O, ENABLE); - if (O !== 1) begin - $error("latch failed"); - $fatal(1); - end - - I = 0; - ENABLE = 0; - # 10 - $display("LATCH_TEST: I=%b O=%b ENABLE=%b", I, O, ENABLE); - if (O !== 1) begin - $error("latch failed"); - $fatal(1); - end - - I = 0; - ENABLE = 1; - # 10 - $display("LATCH_TEST: I=%b O=%b ENABLE=%b", I, O, ENABLE); - if (O !== 0) begin - $error("latch failed"); - $fatal(1); - end - end -endmodule diff --git a/emulator/lib/mux.v b/emulator/lib/mux.v deleted file mode 100644 index acf17b4..0000000 --- a/emulator/lib/mux.v +++ /dev/null @@ -1,55 +0,0 @@ -// MUX 8-bit IO with 1-bit selection -// B is returned when S is active. -module MUX_8_1( - output [7:0] value, - input[7:0] A,B, - input S); - - wire Snot; - not (Snot, S); - - wire [7:0] x; - wire [7:0] y; - and (x[0], A[0], Snot); - and (x[1], A[1], Snot); - and (x[2], A[2], Snot); - and (x[3], A[3], Snot); - and (x[4], A[4], Snot); - and (x[5], A[5], Snot); - and (x[6], A[6], Snot); - and (x[7], A[7], Snot); - - - and (y[0], B[0], S); - and (y[1], B[1], S); - and (y[2], B[2], S); - and (y[3], B[3], S); - and (y[4], B[4], S); - and (y[5], B[5], S); - and (y[6], B[6], S); - and (y[7], B[7], S); - - or (value[0], x[0], y[0]); - or (value[1], x[1], y[1]); - or (value[2], x[2], y[2]); - or (value[3], x[3], y[3]); - or (value[4], x[4], y[4]); - or (value[5], x[5], y[5]); - or (value[6], x[6], y[6]); - or (value[7], x[7], y[7]); - -endmodule - -module MUX_8_2( - output[7:0] value, - input[7:0] A,B,C,D, - input[1:0] S); - - wire[7:0] val_a, val_b; - - MUX_8_1 m1(.value(val_a), .A(A), .B(B), .S(S[0])); - MUX_8_1 m2(.value(val_b), .A(C), .B(D), .S(S[0])); - MUX_8_1 m3(.value(value), .A(val_a), .B(val_b), .S(S[1])); - -endmodule - diff --git a/emulator/lib/mux_test.v b/emulator/lib/mux_test.v deleted file mode 100644 index afa5c09..0000000 --- a/emulator/lib/mux_test.v +++ /dev/null @@ -1,70 +0,0 @@ -`include "emulator/lib/mux.v" - -module mux_8_1_test; - reg[7:0] A = 8'b01100101; - reg[7:0] B = 8'b10101100; - reg S; - wire[7:0] out; - - MUX_8_1 dut(.value(out), .A(A), .B(B), .S(S)); - - initial begin - S = 0; - # 10 - $display("MUX_TEST: A=%b B=%b S=%b OUT=%b", A, B, S, out); - if (out !== A) begin - $error("mux failed"); - $fatal(1); - end - S = 1; - # 10 - $display("MUX_TEST: A=%b B=%b S=%b OUT=%b", A, B, S, out); - if (out !== B) begin - $error("mux failed"); - $fatal(1); - end - end -endmodule - - -module mux_8_2_test; - reg[7:0] A = 8'b11101110; - reg[7:0] B = 8'b11100110; - reg[7:0] C = 8'b11100100; - reg[7:0] D = 8'b00110111; - reg[1:0] S; - wire[7:0] out; - - MUX_8_2 dut(.value(out), .A(A), .B(B), .C(C), .D(D), .S(S)); - - initial begin - S = 0; - # 10 - $display("MUX_TEST: A=%b B=%b S=%b OUT=%b", A, B, S, out); - if (out !== A) begin - $error("mux failed"); - $fatal(1); - end - S = 1; - # 10 - $display("MUX_TEST: A=%b B=%b S=%b OUT=%b", A, B, S, out); - if (out !== B) begin - $error("mux failed"); - $fatal(1); - end - S = 2; - # 10 - $display("MUX_TEST: A=%b B=%b S=%b OUT=%b", A, B, S, out); - if (out !== C) begin - $error("mux failed"); - $fatal(1); - end - S = 3; - # 10 - $display("MUX_TEST: A=%b B=%b S=%b OUT=%b", A, B, S, out); - if (out !== D) begin - $error("mux failed"); - $fatal(1); - end - end -endmodule diff --git a/emulator/module/boot_control.v b/emulator/module/boot_control.v deleted file mode 100644 index 7b376ec..0000000 --- a/emulator/module/boot_control.v +++ /dev/null @@ -1,12 +0,0 @@ -module BOOT_CONTROL(output is_powered_on); - // As we don't have a button to control boot. - // We say boot will automatically get pressed after - // 100 time units. - reg _is_powered_on; - initial begin - assign _is_powered_on = 0; - # 100 - assign _is_powered_on = 1; - end - assign is_powered_on = _is_powered_on; -endmodule \ No newline at end of file diff --git a/emulator/module/boot_control_test.v b/emulator/module/boot_control_test.v deleted file mode 100644 index a9872b9..0000000 --- a/emulator/module/boot_control_test.v +++ /dev/null @@ -1,28 +0,0 @@ -`include "emulator/module/boot_control.v" - -module boot_control_test; - wire is_powered_on; - BOOT_CONTROL dut(.is_powered_on(is_powered_on)); - - initial begin - # 5 - $display("BOOT_CONTROL: is_powered_on=%b", is_powered_on); - if (is_powered_on !== 0) begin - $error("BOOT_CONTROL failed"); - $fatal(1); - end - # 80 - $display("BOOT_CONTROL: is_powered_on=%b", is_powered_on); - if (is_powered_on !== 0) begin - $error("BOOT_CONTROL failed"); - $fatal(1); - end - # 20 - $display("BOOT_CONTROL: is_powered_on=%b", is_powered_on); - if (is_powered_on !== 1) begin - $error("BOOT_CONTROL failed"); - $fatal(1); - end - end -endmodule - diff --git a/emulator/module/clock.v b/emulator/module/clock.v deleted file mode 100644 index 26bb7a5..0000000 --- a/emulator/module/clock.v +++ /dev/null @@ -1,54 +0,0 @@ -module CLOCK( - output[0:3] clk, - output[0:3] is_stage); - - // stages: - // The architecture splits instructions execution in 4 stages. - // stage0: fetch and expand instruction at program_counter. - // stage1: fetch value0 (usually operand0) from desidered source. - // stage2: fetch value1 (usually operand1) from desidered source. - // stage3: write value2 (result) to desidered source and update - // program_counter if and when desired. - // hw_clk (internal): - // clock signal - // clk[0],clk[1],clk[2],clk[3]: - // clk splitted into 4. Each clk{i} posedge represents flipflop write - // of stage{i}. - // e.g. stage1 is active b/w clk0 and clk1 posedge. - - - // TODO: make clock more realistic. - reg[0:3] hw_clk; - reg[0:3] _is_stage; - initial begin - forever begin - #10 - _is_stage[0]=0; - hw_clk[0]=1; - _is_stage[1]=1; - #10 - hw_clk[0]=0; - #10 - _is_stage[1]=0; - hw_clk[1]=1; - _is_stage[2]=1; - #10 - hw_clk[1]=0; - #10 - _is_stage[2]=0; - hw_clk[2]=1; - _is_stage[3]=1; - #10 - hw_clk[2]=0; - #10 - _is_stage[3]=0; - hw_clk[3]=1; - _is_stage[0]=1; - #10 - hw_clk[3]=0; - end - end - - assign clk[0:3] = hw_clk[0:3]; - assign is_stage[0:3] = _is_stage[0:3]; -endmodule diff --git a/emulator/module/clock_test.v b/emulator/module/clock_test.v deleted file mode 100644 index 6b54f31..0000000 --- a/emulator/module/clock_test.v +++ /dev/null @@ -1,44 +0,0 @@ -`include "emulator/module/clock.v" - -module clock_test; - wire[0:3] clk; - wire[0:3] is_stage; - CLOCK dut( - .clk(clk[0:3]), - .is_stage(is_stage[0:3])); - - initial begin - # 75 - $display("CLK: clk=%b is_stage=%b", clk, is_stage); - if (clk !== 4'b0001 || is_stage !== 4'b1000) begin - $error("clock failed"); - $fatal(1); - end - # 20 - $display("CLK: clk=%b is_stage=%b", clk, is_stage); - if (clk !== 4'b1000 || is_stage !== 4'b0100) begin - $error("clock failed"); - $fatal(1); - end - # 20 - $display("CLK: clk=%b is_stage=%b", clk, is_stage); - if (clk !== 4'b0100 || is_stage !== 4'b0010) begin - $error("clock failed"); - $fatal(1); - end - # 20 - $display("CLK: clk=%b is_stage=%b", clk, is_stage); - if (clk !== 4'b0010 || is_stage !== 4'b0001) begin - $error("clock failed"); - $fatal(1); - end - # 20 - $display("CLK: clk=%b is_stage=%b", clk, is_stage); - if (clk !== 4'b0001 || is_stage !== 4'b1000) begin - $error("clock failed"); - $fatal(1); - end - $finish(); - end -endmodule - diff --git a/emulator/module/ipc.v b/emulator/module/ipc.v new file mode 100644 index 0000000..5b82864 --- /dev/null +++ b/emulator/module/ipc.v @@ -0,0 +1,31 @@ +`define INPUT_FILE "/tmp/ourpc_input" + +// Handle Inter Process Communication +// We weren't able to figure out simpler way to do so. +module IPCOut( + input[7:0] device_id, + input[31:0] value + ); + + always @(value) begin + $display("IPC %x %x", device_id, value); + end +endmodule + +module IPCIn( + output[31:0] value, + input[7:0] device_id, + input clk); + + // device_id to value + reg[31:0] _ipc_input[0:7]; + always @(posedge clk) begin + // At some random interval + $readmemb(`INPUT_FILE, _ipc_input); + end + reg[31:0] _value; + always @(*) begin + _value <= _ipc_input[device_id]; + end + assign value = _value; +endmodule diff --git a/emulator/module/ipc_test.v b/emulator/module/ipc_test.v new file mode 100644 index 0000000..c5b3210 --- /dev/null +++ b/emulator/module/ipc_test.v @@ -0,0 +1,57 @@ +`include "emulator/module/ipc.v" + +module ipc_out_test; + reg[7:0] device_id; + reg[31:0] value; + + IPCOut dut(.device_id(device_id[7:0]), .value(value[31:0])); + + initial begin + # 5 + device_id = 10; + # 1 + value = 20; + // Not test here, output goes to stdout. + end +endmodule + +module ipc_in_test; + reg[7:0] device_id; + reg clk; + output[31:0] value; + + IPCIn dut(.value(value[31:0]), .device_id(device_id[7:0]), .clk(clk)); + + integer f; + initial begin + # 5 + f = $fopen("/tmp/ourpc_input", "w"); + $fwrite(f,"00000000000000000000000000000001\n"); + $fwrite(f,"11111111111111111111111111111111\n"); + $fwrite(f,"01010101010101010101010101010101\n"); + $fwrite(f,"10101010101010101010101010101010\n"); + $fwrite(f,"00000000000000000000000011111111\n"); + $fwrite(f,"11111111000000000000000000000000\n"); + $fwrite(f,"01010101101010100101010110101010\n"); + $fwrite(f,"10101010010101011010101001010101\n"); + $fclose(f); + + device_id = 1; + clk = 0; + # 5 + clk = 1; + # 5 + if (value !== 32'b11111111111111111111111111111111) begin + $error("ipc input failed, got: %b", value); + $fatal(1); + end + device_id = 6; + # 1 + if (value !== 32'b01010101101010100101010110101010) begin + $error("ipc input failed, got: %b", value); + $fatal(1); + end + + end +endmodule + diff --git a/emulator/module/mblock/mblock.v b/emulator/module/mblock/mblock.v deleted file mode 100644 index d94ec13..0000000 --- a/emulator/module/mblock/mblock.v +++ /dev/null @@ -1,35 +0,0 @@ -`include "emulator/module/mblock/mconst.v" -`include "emulator/module/mblock/ram.v" -`include "emulator/module/mblock/rom.v" -`include "emulator/lib//mux.v" - -module MBLOCK(output[31:0] out, - input[1:0] selector, - input[31:0] in, - input[15:0] address, - input is_write); - - // TODO: How can be careful about accidental write occurance - // due to race between how the values are propogated? - - wire[31:0] out0, out1, out2, out3; - - ROM_BOOT romb(.out(out0), - .address(address)); - - RAM_32bit_16aline ram(.out(out1), - .in(in), - .address(address), - .is_write(is_write & ~selector[1] & selector[0])); - - // selector 10 is reserved for IO - - MCONST mconst(.out(out3), - .in(address)); - - MUX_8_2 m0(.value(out[ 7: 0]), .A(out0[ 7: 0]), .B(out1[ 7: 0]), .D(out3[ 7: 0]), .S(selector[1:0])); - MUX_8_2 m1(.value(out[15: 8]), .A(out0[15: 8]), .B(out1[15: 8]), .D(out3[15: 8]), .S(selector[1:0])); - MUX_8_2 m2(.value(out[23:16]), .A(out0[23:16]), .B(out1[23:16]), .D(out3[23:16]), .S(selector[1:0])); - MUX_8_2 m3(.value(out[31:24]), .A(out0[31:24]), .B(out1[31:24]), .D(out3[31:24]), .S(selector[1:0])); - -endmodule diff --git a/emulator/module/mblock/mblock_test.v b/emulator/module/mblock/mblock_test.v deleted file mode 100644 index 0b81c30..0000000 --- a/emulator/module/mblock/mblock_test.v +++ /dev/null @@ -1,68 +0,0 @@ -`include "emulator/module/mblock/mblock.v" - -module BLOCK_32bit_16aline_test; - wire[31:0] out; - reg[15:0] address; - reg[1:0] selector; - reg[31:0] in; - reg is_write; - - localparam [31:0] INPUT16z = 16'bzzzzzzzzzzzzzzzz; - localparam [31:0] INPUT32z = 32'bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz; - localparam [31:0] INPUT1 = 32'b11100101111110000100101010110001; - localparam [31:0] INPUT2 = 32'b01011100100011000110101000000001; - - MBLOCK dut(.out(out), - .selector(selector), - .in(in), - .address(address), - .is_write(is_write)); - - initial begin - selector = 2'b01; // RAM write - address = 16'b1011100000111010; - in = INPUT1; - # 10 - is_write = 1; - # 10 - $display("MBLOCK: RAM_TEST: address=%b is_write=%b in=%b out=%b", address, is_write, in, out); - if (out !== INPUT1) begin - $error("mblock failed"); - $fatal(1); - end - - selector = 2'b00; // ROM_BOOT - address = 16'b0000000000000001; - is_write = 1'bz; - in = INPUT32z; - # 10 - $display("MBLOCK: ROM_TEST: address=%b is_write=%b in=%b out=%b", address, is_write, in, out); - if (out !== 32'b11111100101011001101000010101001) begin - $error("mblock failed"); - $fatal(1); - end - - selector = 2'b11; // MCONST - address = 16'b0001100100111101; - is_write = 1'bz; - in = INPUT32z; - # 10 - $display("MBLOCK: MCONST: address=%b is_write=%b in=%b out=%b", address, is_write, in, out); - if (out !== 32'b00000000000000000001100100111101) begin - $error("mblock failed"); - $fatal(1); - end - - selector = 2'b01; // RAM read - address = 16'b1011100000111010; - is_write = 0; - # 10 - in = INPUT32z; - # 10 - $display("MBLOCK: RAM_TEST: address=%b is_write=%b in=%b out=%b", address, is_write, in, out); - if (out !== INPUT1) begin - $error("mblock failed"); - $fatal(1); - end - end -endmodule diff --git a/emulator/module/mblock/mconst.v b/emulator/module/mblock/mconst.v deleted file mode 100644 index f6e8242..0000000 --- a/emulator/module/mblock/mconst.v +++ /dev/null @@ -1,9 +0,0 @@ -module MCONST( - output[31:0] out, - input[15:0] in); - // returns constant value - - assign out[31:16] = 16'b0000000000000000; - assign out[15:0] = in[15:0]; - -endmodule diff --git a/emulator/module/mblock/mconst_test.v b/emulator/module/mblock/mconst_test.v deleted file mode 100644 index b3d6570..0000000 --- a/emulator/module/mblock/mconst_test.v +++ /dev/null @@ -1,26 +0,0 @@ -`include "emulator/module/mblock/mconst.v" - -module MCONST_test; - reg[31:0] in; - wire[31:0] out; - - MCONST dut(.out(out), - .in(in)); - - initial begin - in = 16'b0010111100010010; - # 10 - $display("MCONST_TEST: in=%b out=%b", in, out); - if (out !== 32'b00000000000000000010111100010010) begin - $error("mconst failed"); - $fatal(1); - end - in = 16'b1001011000011000; - # 10 - $display("MCONST_TEST: in=%b out=%b", in, out); - if (out !== 32'b00000000000000001001011000011000) begin - $error("mconst failed"); - $fatal(1); - end - end -endmodule diff --git a/emulator/module/mblock/ram.v b/emulator/module/mblock/ram.v deleted file mode 100644 index 31be343..0000000 --- a/emulator/module/mblock/ram.v +++ /dev/null @@ -1,15 +0,0 @@ -module RAM_32bit_16aline(output[31:0] out, - input[31:0] in, - input[15:0] address, - input is_write); - // 4 * 64KB RAM - - reg[31:0] mem [65535:0]; - always @(address, in, is_write) begin - if (is_write) begin - mem[address] <= in; - end - end - assign out = mem[address]; - -endmodule diff --git a/emulator/module/mblock/rom.v b/emulator/module/mblock/rom.v deleted file mode 100644 index 5fe74c4..0000000 --- a/emulator/module/mblock/rom.v +++ /dev/null @@ -1,26 +0,0 @@ -module _ROM_32bit_16aline( - output[31:0] out, - input[15:0] address); - // 4 * 64KB ROM - - parameter filename = "/dev/null"; - - reg[31:0] buffer[0:65535]; - initial begin - $readmemb(filename, buffer); - $display("ROM: %h", buffer[0]); - end - - assign out = buffer[address]; - -endmodule - -module ROM_BOOT( - output[31:0] out, - input[15:0] address); - // 4 * 64KB ROM - - _ROM_32bit_16aline #(.filename("emulator/module/mblock/rom_boot.bin")) - dut(.out(out), - .address(address)); -endmodule diff --git a/emulator/module/mblock/rom_boot.bin b/emulator/module/mblock/rom_boot.bin deleted file mode 100644 index cfa321f..0000000 --- a/emulator/module/mblock/rom_boot.bin +++ /dev/null @@ -1,10 +0,0 @@ -10000010101111110111100001010111 -11111100101011001101000010101001 -00000001001101101111110110011101 -11111010111111110100000111111110 -00010110010001100011011100001001 -00111110100111011000101110111011 -10000011101110100011100000011000 -10011111011110101000001000101001 -00110101001001011000000100011101 -01110000101110000000100100011101 diff --git a/emulator/module/mblock/rom_test.bin b/emulator/module/mblock/rom_test.bin deleted file mode 100644 index cfa321f..0000000 --- a/emulator/module/mblock/rom_test.bin +++ /dev/null @@ -1,10 +0,0 @@ -10000010101111110111100001010111 -11111100101011001101000010101001 -00000001001101101111110110011101 -11111010111111110100000111111110 -00010110010001100011011100001001 -00111110100111011000101110111011 -10000011101110100011100000011000 -10011111011110101000001000101001 -00110101001001011000000100011101 -01110000101110000000100100011101 diff --git a/emulator/module/mblock/rom_test.v b/emulator/module/mblock/rom_test.v deleted file mode 100644 index 3629dab..0000000 --- a/emulator/module/mblock/rom_test.v +++ /dev/null @@ -1,59 +0,0 @@ -`include "emulator/module/mblock/rom.v" - -module rom_test; - reg[15:0] address; - wire[31:0] out; - - _ROM_32bit_16aline #(.filename("emulator/module/mblock/rom_test.bin")) - dut(.out(out), - .address(address)); - - initial begin - address = 0; - # 10 - $display("ROM_TEST: address=%b out=%b", address, out); - if (out !== 32'b10000010101111110111100001010111) begin - $error("rom failed"); - $fatal(1); - end - address = 1; - # 10 - $display("ROM_TEST: address=%b out=%b", address, out); - if (out !== 32'b11111100101011001101000010101001) begin - $error("rom failed"); - $fatal(1); - end - address = 3; - # 10 - $display("ROM_TEST: address=%b out=%b", address, out); - if (out !== 32'b11111010111111110100000111111110) begin - $error("rom failed"); - $fatal(1); - end - address = 7; - # 10 - $display("ROM_TEST: address=%b out=%b", address, out); - if (out !== 32'b10011111011110101000001000101001) begin - $error("rom failed"); - $fatal(1); - end - end -endmodule - -module rom_boot_test; - reg[15:0] address; - wire[31:0] out; - - ROM_BOOT dut(.out(out), - .address(address)); - - initial begin - address = 0; - # 10 - $display("ROM_TEST: address=%b out=%b", address, out); - if (out !== 32'b10000010101111110111100001010111) begin - $error("rom failed"); - $fatal(1); - end - end -endmodule diff --git a/emulator/module/mblock_mux.v b/emulator/module/mblock_mux.v deleted file mode 100644 index a0dec38..0000000 --- a/emulator/module/mblock_mux.v +++ /dev/null @@ -1,56 +0,0 @@ -module MBLOCK_MUX(output[31:0] mblock_address, - output[1:0] mblock_selector, - - input execute_from_brom, - input[0:3] is_stage, - input[15:0] address0, // program_counter - input[15:0] address1, // v0_source - input[15:0] address2, // v1_source - input[15:0] address3, // v2_source - input[3:0] is_write, - ); - - // TODO Starts - // TODO: We should support I/O and const in mblock_selector - // during stage0, before stage0 posedge - // mblock_selector[0] = execute_from_brom; - // mblock_selector[1] = 0; - // after stage0 posedge - // mblock_selector = will come from instruction_op - // after stage1 posedge - // mblock_selector = will come from instruction_op - // after stage2 posedge - // mblock_selector = will come from instruction_op - // Challenge: How will we will fit, 3 mux_selector, ALU_OP and - // instructions classes all within 1 byte... - // TODO Ends - - always @(is_stage, is_write, address0, address1, address2, address3) - begin - if (is_stage == 2'b00) - begin - // Active RAM or BROM based upon $execute_from_brom. - assign mblock_selector[1:0] = {0, execute_from_brom}; - end - else if (is_stage == 2'b01) - begin - // TODO: mblock_selector compute from instruction_op - end - else if (is_stage == 2'b10) - begin - // TODO: mblock_selector compute from instruction_op - end - else - begin - // TODO: mblock_selector compute from instruction_op - end - else - - end - - MUX_8_2 m0(.value(mblock_address[ 7: 0]), .A(address0[ 7: 0]), .B(address1[ 7: 0]), ,C(address2[ 7: 0]), .D(address3[ 7: 0]), .S(mblock_selector[1:0])); - MUX_8_2 m1(.value(mblock_address[15: 8]), .A(address0[15: 8]), .B(address1[15: 8]), ,C(address2[15: 8]), .D(address3[15: 8]), .S(mblock_selector[1:0])); - MUX_8_2 m2(.value(mblock_address[23:16]), .A(address0[23:16]), .B(address1[23:16]), ,C(address2[23:16]), .D(address3[23:16]), .S(mblock_selector[1:0])); - MUX_8_2 m3(.value(mblock_address[31:24]), .A(address0[31:24]), .B(address1[31:24]), ,C(address2[31:24]), .D(address3[31:24]), .S(mblock_selector[1:0])); - -endmodule diff --git a/emulator/module/pc_next.v b/emulator/module/pc_next.v deleted file mode 100644 index 97f60fc..0000000 --- a/emulator/module/pc_next.v +++ /dev/null @@ -1,37 +0,0 @@ -module PC_NEXT( - inout [15:0] program_counter, - input is_powered_on, - input clk); - - // TODO: we should support jmp like instructions. - - wire[15:0] program_counter_plus_one; - wire[15:0] program_counter_next; - - ADDER pc_adder( - .out(program_counter_plus_one), - .in0(program_counter), - .in1(1)); - - AND(program_counter_next[00], program_counter_plus_one[00], is_powered_on); - AND(program_counter_next[01], program_counter_plus_one[01], is_powered_on); - AND(program_counter_next[02], program_counter_plus_one[02], is_powered_on); - AND(program_counter_next[03], program_counter_plus_one[03], is_powered_on); - AND(program_counter_next[04], program_counter_plus_one[04], is_powered_on); - AND(program_counter_next[05], program_counter_plus_one[05], is_powered_on); - AND(program_counter_next[06], program_counter_plus_one[06], is_powered_on); - AND(program_counter_next[07], program_counter_plus_one[07], is_powered_on); - AND(program_counter_next[08], program_counter_plus_one[08], is_powered_on); - AND(program_counter_next[09], program_counter_plus_one[09], is_powered_on); - AND(program_counter_next[10], program_counter_plus_one[10], is_powered_on); - AND(program_counter_next[11], program_counter_plus_one[11], is_powered_on); - AND(program_counter_next[12], program_counter_plus_one[12], is_powered_on); - AND(program_counter_next[13], program_counter_plus_one[13], is_powered_on); - AND(program_counter_next[14], program_counter_plus_one[14], is_powered_on); - AND(program_counter_next[15], program_counter_plus_one[15], is_powered_on); - - flipflop16 pc( - .out(program_counter), - .in(program_counter_next), - .clk(clk)); -endmodule diff --git a/emulator/module/stage0_ins_resolver.v b/emulator/module/stage0_ins_resolver.v deleted file mode 100644 index 083c61b..0000000 --- a/emulator/module/stage0_ins_resolver.v +++ /dev/null @@ -1,14 +0,0 @@ -module INS_RESOLVER(output[7:0] v0, v1, v2, op, - input[32:0] full_ins, - input clk); - - wire[31:0] mem_ins; - flipflop32 f(.out(mem_ins[31:0]), .in(full_ins[31:0]), .clk(clk)); - - assign v0[7:0] = full_ins[ 7: 0]; - assign v1[7:0] = full_ins[15: 8]; - // TODO: v2_source can be drived from v1 - assign v2[7:0] = full_ins[23:16]; - assign op[7:0] = full_ins[31:24]; - -endmodule diff --git a/emulator/module/stage1or2_store.v b/emulator/module/stage1or2_store.v deleted file mode 100644 index f36ea0e..0000000 --- a/emulator/module/stage1or2_store.v +++ /dev/null @@ -1,7 +0,0 @@ -module FETCH_AND_STORE(output[31:0] value, - input[31:0] in, - input clk); - - flipflop32 f(.out(value[31:0]), .in(in[31:0]), .clk(clk)); - -endmodule diff --git a/emulator/seq/clock.v b/emulator/seq/clock.v new file mode 100644 index 0000000..44c1d1e --- /dev/null +++ b/emulator/seq/clock.v @@ -0,0 +1,65 @@ +module CLOCK( + output[0:3] clk, + output[1:0] clk_stage); + + // stages: + // The architecture splits instructions execution in 4 stages. + // stage0: fetch and expand instruction at program_counter. + // stage1: fetch vr_value from desidered source. + // stage2: fetch vrw_value from desidered source. + // stage3: write vw_value (result) to desidered source or pc. + // hw_clk (internal): + // clock signal which controls clk[0:3] + // clk[0],clk[1],clk[2],clk[3]: + // clk splitted into 4 + // The order of edges and active state. + // - clk[0] up + // - clk[0] down + // - clk[1] up + // - clk[1] down + // - clk[2] up + // - clk[2] down + // - clk[3] up + // - clk[3] down + + reg hw_clk; + reg[0:3] _clk; + reg[1:0] _clk_stage; + integer _count; + + initial begin + hw_clk = 0; + _count = 0; + forever begin + #10 hw_clk = ~hw_clk; + end + end + + always @(posedge hw_clk) begin + _count <= _count + 1; + if (_count == 0) begin + assign _clk[0] = 1; + assign _clk_stage = 0; + end + if (_count == 1) begin + assign _clk[1] = 1; + assign _clk_stage = 1; + end + if (_count == 2) begin + assign _clk[2] = 1; + assign _clk_stage = 2; + end + if (_count == 3) begin + assign _clk[3] = 1; + assign _clk_stage = 3; + _count <= 0; + end + end + + always @(negedge hw_clk) begin + assign _clk[0:3] = 4'b0000; + end + + assign clk[0:3] = _clk[0:3]; + assign clk_stage = _clk_stage; +endmodule diff --git a/emulator/seq/clock_test.v b/emulator/seq/clock_test.v new file mode 100644 index 0000000..319e766 --- /dev/null +++ b/emulator/seq/clock_test.v @@ -0,0 +1,37 @@ +`include "emulator/seq/clock.v" + +module clock_test; + wire[0:3] clk; + wire[1:0] clk_stage; + CLOCK dut(.clk(clk[0:3]), .clk_stage(clk_stage)); + + initial begin + # 80 + # 15 + $display("CLK: clk=%b, clk_stage=%b", clk, clk_stage); + if (clk !== 4'b1000 || clk_stage !== 0) begin + $error("clock failed"); + $fatal(1); + end + # 20 + $display("CLK: clk=%b, clk_stage=%b", clk, clk_stage); + if (clk !== 4'b0100 || clk_stage !== 1) begin + $error("clock failed"); + $fatal(1); + end + # 20 + $display("CLK: clk=%b, clk_stage=%b", clk, clk_stage); + if (clk !== 4'b0010 || clk_stage !== 2) begin + $error("clock failed"); + $fatal(1); + end + # 20 + $display("CLK: clk=%b, clk_stage=%b", clk, clk_stage); + if (clk !== 4'b0001 || clk_stage !== 3) begin + $error("clock failed"); + $fatal(1); + end + $finish(); + end +endmodule + diff --git a/emulator/seq/io_devices.v b/emulator/seq/io_devices.v new file mode 100644 index 0000000..a946014 --- /dev/null +++ b/emulator/seq/io_devices.v @@ -0,0 +1,47 @@ +`include "emulator/com/rom.v" +`include "emulator/module/ipc.v" +`define CONSDEV_ID 3 +`define PROM_ID 2 + +module IODevices( + output[31:0] value_out, + input[7:0] device_id, + input[31:0] value_in, + input is_write, + input clk); + + integer fio; + + reg[31:0] value; + output[31:0] value_ipc_in; + + IPCOut ipcout(.device_id(device_id[7:0]), .value(value[31:0])); + IPCIn ipcin(.value(value_ipc_in[31:0]), .device_id(device_id[7:0]), .clk(clk)); + + always @(negedge clk) begin + // Write are triggered at negedge + if (is_write) begin + value <= value_in; + $display("IO:output[%x] <= %x", device_id, value_in); + end + end + + // PROM + wire[31:0] prom_value; + ROM_PINGPONG prom(.out(prom_value), .address(value_in[15:0])); + + reg[31:0] _value; + always @(clk) begin + case (device_id) + // TODO: Is it ok to use continous circuit with value_in as address? + `PROM_ID: _value <= prom_value; + `CONSDEV_ID: _value <= value_in; + default: + // Goes via IPC + begin + _value <= value_ipc_in; + end + endcase + end + assign value_out = _value; +endmodule diff --git a/emulator/seq/io_devices_test.v b/emulator/seq/io_devices_test.v new file mode 100644 index 0000000..839eb67 --- /dev/null +++ b/emulator/seq/io_devices_test.v @@ -0,0 +1,65 @@ +`include "emulator/seq/io_devices.v" + +module IODevices_test; + wire[31:0] value_out; + + reg[7:0] device_id; + reg[31:0] value_in; + reg is_write; + reg clk; + + IODevices dut( + .value_out(value_out), + .device_id(device_id), + .value_in(value_in), + .is_write(is_write), + .clk(clk)); + + localparam [31:0] INPUT1 = 32'b11100101111110000100101010110001; + localparam [31:0] INPUT2 = 32'b01011100100011000110101000000001; + + initial begin + device_id = 1; + is_write = 0; + value_in = INPUT1; + clk = 1; + # 10 + clk = 0; + # 10 + device_id = 3; // const + # 1 + clk = 1; + # 1 + clk = 0; + # 5 + $display("IO_DEVICES_TEST: device_id=%b value_out=%b", device_id, value_out); + if (value_out !== INPUT1) begin + $error("io failed"); + $fatal(1); + end + # 10 + device_id = 2; // PROM + value_in = 0; + # 1 + clk = 1; + # 1 + clk = 0; + # 10 + $display("IO_DEVICES_TEST: device_id=%b value_out=%b", device_id, value_out); + if (value_out === INPUT1) begin + // not a great test but ok. + $error("io failed"); + $fatal(1); + end + # 10 + device_id = 5; // IPC + value_in = 10; + is_write = 1; + # 10 + clk = 0; + # 10 + clk = 1; + // trigger write + // no verification, but it should generate logs. + end +endmodule diff --git a/emulator/seq/ram.v b/emulator/seq/ram.v new file mode 100644 index 0000000..58650b3 --- /dev/null +++ b/emulator/seq/ram.v @@ -0,0 +1,19 @@ +module RAM_32bit_16aline( + output[31:0] out, + input[31:0] in, + input[15:0] address, + input is_write, + input clk); + // 64KB RAM + + reg[31:0] mem [65535:0]; + always @(negedge clk) begin + // Write are triggered at negedge + if (is_write) begin + mem[address] <= in; + $display("RAM[%x] <= %x", address, in); + end + end + assign out = mem[address]; + +endmodule diff --git a/emulator/module/mblock/ram_test.v b/emulator/seq/ram_test.v similarity index 88% rename from emulator/module/mblock/ram_test.v rename to emulator/seq/ram_test.v index d4cfb5b..f1648cb 100644 --- a/emulator/module/mblock/ram_test.v +++ b/emulator/seq/ram_test.v @@ -1,8 +1,9 @@ -`include "emulator/module/mblock/ram.v" +`include "emulator/seq/ram.v" module RAM_32bit_16aline_test; reg[15:0] address; reg is_write; + reg clk; reg[31:0] in; wire[31:0] out; @@ -12,12 +13,16 @@ module RAM_32bit_16aline_test; RAM_32bit_16aline dut(.out(out), .in(in), .address(address), - .is_write(is_write)); + .is_write(is_write), + .clk(clk)); initial begin address = 16'b1100001110111100; is_write = 1; in = INPUT1; + clk = 1; + # 10 + clk = 0; # 10 $display("RAM_TEST: address=%b is_write=%b in=%b out=%b", address, is_write, in, out); if (out !== INPUT1) begin @@ -30,6 +35,9 @@ module RAM_32bit_16aline_test; # 10 in = INPUT2; # 10 + clk = 1; + # 10 + clk = 0; $display("RAM_TEST: address=%b is_write=%b in=%b out=%b", address, is_write, in, out); if (out !== INPUT1) begin $error("ram failed"); @@ -41,6 +49,10 @@ module RAM_32bit_16aline_test; # 10 is_write = 1; # 10 + clk = 1; + # 10 + clk = 0; + # 10 $display("RAM_TEST: address=%b is_write=%b in=%b out=%b", address, is_write, in, out); if (out !== INPUT2) begin $error("ram failed"); @@ -48,7 +60,6 @@ module RAM_32bit_16aline_test; end is_write = 0; - # 10 address = 16'b1100001110111100; # 10 $display("RAM_TEST: address=%b is_write=%b in=%b out=%b", address, is_write, in, out); diff --git a/emulator/seq/register.v b/emulator/seq/register.v new file mode 100644 index 0000000..bb93efc --- /dev/null +++ b/emulator/seq/register.v @@ -0,0 +1,23 @@ +module REGISTER_up_16b( + output [15:0] out, + input [15:0] in, + input clk); + + reg [15:0] _data; + always @(posedge clk) begin + _data = in; + end + assign out = _data; +endmodule + +module REGISTER_down_16b( + output [15:0] out, + input [15:0] in, + input clk); + + reg [15:0] _data; + always @(negedge clk) begin + _data = in; + end + assign out = _data; +endmodule diff --git a/emulator/seq/register_test.v b/emulator/seq/register_test.v new file mode 100644 index 0000000..d0ca82f --- /dev/null +++ b/emulator/seq/register_test.v @@ -0,0 +1,63 @@ +`include "emulator/seq/register.v" + +module register_up_test; + reg[15:0] in = 16'b0110010101100101; + reg clk; + wire[15:0] out; + + REGISTER_up_16b dut(.out(out), .in(in), .clk(clk)); + + initial begin + clk = 0; + # 10 + clk = 1; + # 1 + clk = 0; + # 1 + in = 16'b1010110010101100; + # 1 + $display("REGISTER_UP_TEST: in=%b out=%b clk=%b", in, out, clk); + if (out !== 16'b0110010101100101) begin // old value + $error("register failed"); + $fatal(1); + end + clk = 1; + # 10 + $display("REGISTER_UP_TEST: in=%b out=%b clk=%b", in, out, clk); + if (out !== 16'b1010110010101100) begin + $error("register failed"); + $fatal(1); + end + end +endmodule + +module register_down_test; + reg[15:0] in = 16'b0110010101100101; + reg clk; + wire[15:0] out; + + REGISTER_down_16b dut(.out(out), .in(in), .clk(clk)); + + initial begin + clk = 1; + # 10 + clk = 0; + # 1 + clk = 1; + # 1 + in = 16'b1010110010101100; + # 1 + $display("REGISTER_DOWN_TEST: in=%b out=%b clk=%b", in, out, clk); + if (out !== 16'b0110010101100101) begin // old value + $error("register failed"); + $fatal(1); + end + clk = 0; + # 10 + $display("REGISTER_DOWN_TEST: in=%b out=%b clk=%b", in, out, clk); + if (out !== 16'b1010110010101100) begin + $error("register failed"); + $fatal(1); + end + end +endmodule diff --git a/emulator/specs.py b/emulator/specs.py deleted file mode 100644 index 04c48ea..0000000 --- a/emulator/specs.py +++ /dev/null @@ -1,8 +0,0 @@ -RAM_ADDRESS_LINES = 16 -ROM_ADDRESS_LINES = 8 - -WORD_SIZE = 8 -ROM_MAXSIZE = 2**(ROM_ADDRESS_LINES) * 8 -RAM_SIZE = 2**(RAM_ADDRESS_LINES) * 8 - -PROGRAM_START = 0x20 diff --git a/output/programs/3_led_switch.bin b/output/programs/3_led_switch.bin index 334da93..8d09d84 100644 --- a/output/programs/3_led_switch.bin +++ b/output/programs/3_led_switch.bin @@ -1,4 +1,4 @@ 00001100 00000000 00000000 00000000 00100100 00000010 00000100 00000101 00000100 00000100 00000110 00000100 -00110101 00001001 01000000 00000000 +10110101 00001001 01000000 00000000 diff --git a/output/programs/boot_sequence.bin b/output/programs/boot_sequence.bin index 9d8f26a..4260dcb 100644 --- a/output/programs/boot_sequence.bin +++ b/output/programs/boot_sequence.bin @@ -1,17 +1,18 @@ -01000000 00000000 00000000 00000000 +01000100 00000000 00000000 00000000 00110100 00000010 00000000 00000000 00000100 00000100 00000010 00000000 00100100 00000010 00000000 00000010 -01110011 00000010 00000000 00000010 +00110011 00000010 00000000 00000010 00110100 00000010 00000100 00000100 00110100 00000010 00001000 10000000 -01110001 00000000 00000000 00000000 -00110101 00001011 01110000 00000000 00000100 00000100 00000010 00000100 00100100 00000010 00001100 00000010 -01000100 00000110 00001000 00001100 -01110000 00000010 00001000 00000100 -01110000 00000010 00000100 00000100 -01110001 00000010 00000000 00000001 -00110101 00001001 01001100 00000000 -00110101 00001001 10000000 00000000 +00000100 00000110 00001000 00001100 +00110000 00000010 00001000 00000100 +00110000 00000010 00000100 00000100 +00110001 00000010 00000000 00000001 +10110101 00001101 01011100 00000000 +00110100 00000010 00100000 00000011 +00110010 00000010 00100000 00001000 +00110111 00000010 00100000 11111100 +10110101 00001001 10000000 00000000 diff --git a/output/programs/boot_sequence_resolved.asm b/output/programs/boot_sequence_resolved.asm index c53cfc2..f1d8e4e 100644 --- a/output/programs/boot_sequence_resolved.asm +++ b/output/programs/boot_sequence_resolved.asm @@ -1,17 +1,18 @@ -PROGRAM_ORG equ 52 -034: MOVC [0], 0 -038: OUT 2, [0] -03c: IN [0], 2 -040: SHRC [0], 2 -044: MOVC [4], 4 -048: MOVC [8], 128 -04c: CMPC [0], 0 -050: JZ 112, 0 -054: OUT 2, [4] -058: IN [12], 2 -05c: STORE [[8]], [12] -060: ADDC [8], 4 -064: ADDC [4], 4 -068: SUBC [0], 1 -06c: JMP 76, 0 -070: JMP 128, 0 +PROGRAM_ORG equ 68 +044: MOVC [0], 0 +048: OUT 2, [0] +04c: IN [0], 2 +050: SHRC [0], 2 +054: MOVC [4], 4 +058: MOVC [8], 128 +05c: OUT 2, [4] +060: IN [12], 2 +064: STORE [[8]], [12] +068: ADDC [8], 4 +06c: ADDC [4], 4 +070: SUBC [0], 1 +074: JNZ 92, 0 +078: MOVC [32], 3 +07c: SHLC [32], 8 +080: ORC [32], 252 +084: JMP 128, 0 diff --git a/output/programs/ping_pong.bin b/output/programs/ping_pong.bin index 195cf60..7ae869c 100644 --- a/output/programs/ping_pong.bin +++ b/output/programs/ping_pong.bin @@ -1,8 +1,5 @@ -00010100 00000011 00000000 00000000 -00110100 00000010 00100000 11111111 -01110010 00000010 00100000 00001000 -01110111 00000010 00100000 11110000 -00110101 00001001 11000000 00000000 +00001000 00000011 00000000 00000000 +10110101 00001001 10110100 00000000 00000010 00000000 00000000 00000000 00000010 00000000 00000000 00000000 00000111 00000000 00000000 00000000 @@ -15,184 +12,184 @@ 11111111 01111111 00000000 00000000 11111110 11111111 00000000 00000000 11111111 11111111 00000000 00000000 -01110000 00000011 00101000 00010000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 00101000 -00110101 00001001 10101000 00000001 -01110000 00000011 00101000 00010000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 00101000 -00110101 00001001 00111000 00000001 -01110000 00000011 00101000 00010000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 00101000 -00110101 00001001 00111100 00000010 -00110101 00001001 11000000 00000000 -01110000 00000011 00101000 00010000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 00101000 -00110101 00001001 00011000 00000001 -01110000 00000011 00101000 00010000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 00101000 -00110101 00001001 10101000 00000001 -00110101 00001001 11110100 00000000 -01110001 00000000 10101100 00000000 -00110101 00001101 00101000 00000001 -01111000 00000010 10110000 00000001 -00110100 00000010 10101100 00001111 -01110001 00000010 10101100 00000001 -10000101 00000010 00101000 00100000 -01110000 00000010 00100000 00000100 -11110101 00001000 00101000 00000000 +11110000 00000011 00101000 00010000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 00101000 +10110101 00001001 10011100 00000001 +11110000 00000011 00101000 00010000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 00101000 +10110101 00001001 00101100 00000001 +11110000 00000011 00101000 00010000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 00101000 +10110101 00001001 00110000 00000010 +10110101 00001001 10110100 00000000 +11110000 00000011 00101000 00010000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 00101000 +10110101 00001001 00001100 00000001 +11110000 00000011 00101000 00010000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 00101000 +10110101 00001001 10011100 00000001 +10110101 00001001 11101000 00000000 +00110001 00000000 10100000 00000000 +10110101 00001101 00011100 00000001 +00111000 00000010 10100100 00000001 +00110100 00000010 10100000 00001111 +00110001 00000010 10100000 00000001 +01000101 00000010 00101000 00100000 +00110000 00000010 00100000 00000100 +10110101 00001000 00101000 00000000 00100100 00000010 00000000 00000001 00110100 00000010 00000100 00000001 -01000110 00000010 00000100 00000000 -00110101 00001011 01010100 00000001 -01110001 00000000 10010000 00000000 -00110101 00001011 01010100 00000001 -01110001 00000010 10010000 00000001 +00000110 00000010 00000100 00000000 +10110101 00001011 01001000 00000001 +00110001 00000000 10000100 00000000 +10110101 00001011 01001000 00000001 +00110001 00000010 10000100 00000001 00110100 00000010 00000100 00000010 -01000110 00000010 00000100 00000000 -00110101 00001011 01101100 00000001 -01110001 00000000 10010000 00000101 -00110101 00001011 01101100 00000001 -01110000 00000010 10010000 00000001 +00000110 00000010 00000100 00000000 +10110101 00001011 01100000 00000001 +00110001 00000000 10000100 00000101 +10110101 00001011 01100000 00000001 +00110000 00000010 10000100 00000001 00110100 00000010 00000100 00000100 -01000110 00000010 00000100 00000000 -00110101 00001011 10000100 00000001 -01110001 00000000 10010100 00000000 -00110101 00001011 10000100 00000001 -01110001 00000010 10010100 00000001 +00000110 00000010 00000100 00000000 +10110101 00001011 01111000 00000001 +00110001 00000000 10001000 00000000 +10110101 00001011 01111000 00000001 +00110001 00000010 10001000 00000001 00110100 00000010 00000100 00001000 -01000110 00000010 00000100 00000000 -00110101 00001011 10011100 00000001 -01110001 00000000 10010100 00000101 -00110101 00001011 10011100 00000001 -01110000 00000010 10010100 00000001 -10000101 00000010 00101000 00100000 -01110000 00000010 00100000 00000100 -11110101 00001000 00101000 00000000 -01110001 00000000 10110000 00000000 -00110101 00001011 11111000 00000001 -00000100 00000010 00000000 10110100 +00000110 00000010 00000100 00000000 +10110101 00001011 10010000 00000001 +00110001 00000000 10001000 00000101 +10110101 00001011 10010000 00000001 +00110000 00000010 10001000 00000001 +01000101 00000010 00101000 00100000 +00110000 00000010 00100000 00000100 +10110101 00001000 00101000 00000000 +00110001 00000000 10100100 00000000 +10110101 00001011 11101100 00000001 +00000100 00000010 00000000 10101000 00110100 00000010 00000100 00000111 -01000010 00000010 00000100 10010000 +00000010 00000010 00000100 10000100 00000100 00000100 00000110 00000000 00000100 00000100 00000111 00000100 00110100 00000010 00000100 00000000 -00000100 00000010 00000000 10111100 +00000100 00000010 00000000 10110000 00000100 00000100 00000111 00000100 00000100 00000100 00000110 00000000 -00000100 00000010 00000000 10111000 +00000100 00000010 00000000 10101100 00110100 00000010 00000100 00000111 -01000010 00000010 00000100 10010100 +00000010 00000010 00000100 10001000 00000100 00000100 00000110 00000000 00000100 00000100 00000111 00000100 00110100 00000010 00000100 00000000 -00000100 00000010 00000000 10111100 +00000100 00000010 00000000 10110000 00000100 00000100 00000111 00000100 00000100 00000100 00000110 00000000 -00000100 00000010 00000000 10011000 +00000100 00000010 00000000 10001100 00110100 00000010 00000100 10000000 -01110010 00000010 00000100 00001000 -01000011 00000010 00000100 00000000 -01001000 00000010 00000100 10100000 -00000100 00000010 00000000 10011100 +00110010 00000010 00000100 00001000 +00000011 00000010 00000100 00000000 +00001000 00000010 00000100 10010100 +00000100 00000010 00000000 10010000 00110100 00000010 00001000 00000001 -01000010 00000010 00001000 00000000 +00000010 00000010 00001000 00000000 00000100 00000100 00000110 00000100 00000100 00000100 00000111 00001000 00110100 00000010 00001000 00000000 -00000100 00000010 00000100 10111100 +00000100 00000010 00000100 10110000 00000100 00000100 00000111 00001000 00000100 00000100 00000110 00000100 -10000101 00000010 00101000 00100000 -01110000 00000010 00100000 00000100 -11110101 00001000 00101000 00000000 -01110001 00000000 10100100 00000000 -00110101 00001101 01011000 00000010 -00110100 00000010 10100100 00000011 -01110000 00000011 00101000 00010000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 00101000 -00110101 00001001 01101000 00000010 -01110001 00000010 10100100 00000001 -10000101 00000010 00101000 00100000 -01110000 00000010 00100000 00000100 -11110101 00001000 00101000 00000000 -01110001 00000000 10011000 00001110 -00110101 00001011 11001100 00000010 -01110001 00000000 10011000 00000001 -00110101 00001011 11110000 00000010 -01110001 00000000 10011100 00000111 -00110101 00001011 10000000 00000011 -01110001 00000000 10011100 00000000 -00110101 00001011 10000000 00000011 -00000100 00000010 00000000 10101000 -01110110 00000010 00000000 00000001 -00110101 00001011 10011100 00000010 -01110000 00000010 10011000 00000001 -00110101 00001001 10100000 00000010 -01110001 00000010 10011000 00000001 -00000100 00000010 00000000 10101000 -01110110 00000010 00000000 00000100 -00110101 00001011 10110000 00000010 -01110001 00000010 10011100 00000001 -00000100 00000010 00000000 10101000 -01110110 00000010 00000000 00001000 -00110101 00001011 11000000 00000010 -01110000 00000010 10011100 00000001 -10000101 00000010 00101000 00100000 -01110000 00000010 00100000 00000100 -11110101 00001000 00101000 00000000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 10010100 -01110000 00000011 00101000 00010000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 00101000 -00110101 00001001 00010100 00000011 -10000101 00000010 00011100 00100000 -01110000 00000010 00100000 00000100 -00110101 00001001 01111000 00000010 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 10010000 -01110000 00000011 00101000 00010000 -01110001 00000010 00100000 00000100 -01000100 00000110 00100000 00101000 -00110101 00001001 00010100 00000011 -10000101 00000010 00011100 00100000 -01110000 00000010 00100000 00000100 -00110101 00001001 01111000 00000010 +01000101 00000010 00101000 00100000 +00110000 00000010 00100000 00000100 +10110101 00001000 00101000 00000000 +00110001 00000000 10011000 00000000 +10110101 00001101 01001100 00000010 +00110100 00000010 10011000 00000011 +11110000 00000011 00101000 00010000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 00101000 +10110101 00001001 01011100 00000010 +00110001 00000010 10011000 00000001 +01000101 00000010 00101000 00100000 +00110000 00000010 00100000 00000100 +10110101 00001000 00101000 00000000 +00110001 00000000 10001100 00001110 +10110101 00001011 11000000 00000010 +00110001 00000000 10001100 00000001 +10110101 00001011 11100100 00000010 +00110001 00000000 10010000 00000111 +10110101 00001011 01110100 00000011 +00110001 00000000 10010000 00000000 +10110101 00001011 01110100 00000011 +00000100 00000010 00000000 10011100 +00110110 00000010 00000000 00000001 +10110101 00001011 10010000 00000010 +00110000 00000010 10001100 00000001 +10110101 00001001 10010100 00000010 +00110001 00000010 10001100 00000001 +00000100 00000010 00000000 10011100 +00110110 00000010 00000000 00000100 +10110101 00001011 10100100 00000010 +00110001 00000010 10010000 00000001 +00000100 00000010 00000000 10011100 +00110110 00000010 00000000 00001000 +10110101 00001011 10110100 00000010 +00110000 00000010 10010000 00000001 +01000101 00000010 00101000 00100000 +00110000 00000010 00100000 00000100 +10110101 00001000 00101000 00000000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 10001000 +11110000 00000011 00101000 00010000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 00101000 +10110101 00001001 00001000 00000011 +01000101 00000010 00011100 00100000 +00110000 00000010 00100000 00000100 +10110101 00001001 01101100 00000010 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 10000100 +11110000 00000011 00101000 00010000 +00110001 00000010 00100000 00000100 +00000100 00000110 00100000 00101000 +10110101 00001001 00001000 00000011 +01000101 00000010 00011100 00100000 +00110000 00000010 00100000 00000100 +10110101 00001001 01101100 00000010 00000100 00000010 00100100 00100000 -01110000 00000010 00100100 00000100 -10000101 00000010 00000100 00100100 -01111000 00000010 10101000 00000011 +00110000 00000010 00100100 00000100 +01000101 00000010 00000100 00100100 +00111000 00000010 10011100 00000011 00110100 00000010 00000000 00001100 -01111000 00000010 00000000 11111111 -01000110 00000010 10101000 00000000 -01000001 00000000 10011100 00000100 -00110101 00001011 01010100 00000011 -01110000 00000010 00000100 00000001 -01000001 00000000 10011100 00000100 -00110101 00001011 01110100 00000011 -01110000 00000010 00000100 00000001 -01000001 00000000 10011100 00000100 -00110101 00001011 01100100 00000011 -00110101 00001001 11110100 00000000 -01110111 00000010 10101000 00000100 -10000101 00000010 00101000 00100000 -01110000 00000010 00100000 00000100 -11110101 00001000 00101000 00000000 -01110111 00000010 10101000 00001000 -10000101 00000010 00101000 00100000 -01110000 00000010 00100000 00000100 -11110101 00001000 00101000 00000000 -10000101 00000010 00101000 00100000 -01110000 00000010 00100000 00000100 -11110101 00001000 00101000 00000000 -00000100 00000010 00000000 10101000 -01110110 00000010 00000000 00001100 -00110101 00001011 10001000 00000010 -01111000 00000010 10101000 00001100 -00110101 00001001 10001000 00000010 +00111000 00000010 00000000 11111111 +00000110 00000010 10011100 00000000 +00000001 00000000 10010000 00000100 +10110101 00001011 01001000 00000011 +00110000 00000010 00000100 00000001 +00000001 00000000 10010000 00000100 +10110101 00001011 01101000 00000011 +00110000 00000010 00000100 00000001 +00000001 00000000 10010000 00000100 +10110101 00001011 01011000 00000011 +10110101 00001001 11101000 00000000 +00110111 00000010 10011100 00000100 +01000101 00000010 00101000 00100000 +00110000 00000010 00100000 00000100 +10110101 00001000 00101000 00000000 +00110111 00000010 10011100 00001000 +01000101 00000010 00101000 00100000 +00110000 00000010 00100000 00000100 +10110101 00001000 00101000 00000000 +01000101 00000010 00101000 00100000 +00110000 00000010 00100000 00000100 +10110101 00001000 00101000 00000000 +00000100 00000010 00000000 10011100 +00110110 00000010 00000000 00001100 +10110101 00001011 01111100 00000010 +00111000 00000010 10011100 00001100 +10110101 00001001 01111100 00000010 diff --git a/output/programs/ping_pong_resolved.asm b/output/programs/ping_pong_resolved.asm index b8f0c8f..cc870f1 100644 --- a/output/programs/ping_pong_resolved.asm +++ b/output/programs/ping_pong_resolved.asm @@ -1,234 +1,231 @@ PROGRAM_ORG equ 128 -080: MOVC [32], 255 -084: SHLC [32], 8 -088: ORC [32], 240 -08c: JMP 192, 0 +080: JMP 180, 0 +084: 02 +085: 00 +086: 00 +087: 00 +088: 02 +089: 00 +08a: 00 +08b: 00 +08c: 07 +08d: 00 +08e: 00 +08f: 00 090: 02 091: 00 092: 00 093: 00 -094: 02 -095: 00 +094: 255 +095: 255 096: 00 097: 00 -098: 07 +098: 00 099: 00 09a: 00 09b: 00 -09c: 02 +09c: 06 09d: 00 09e: 00 09f: 00 -0a0: 255 -0a1: 255 +0a0: 00 +0a1: 00 0a2: 00 0a3: 00 -0a4: 00 +0a4: 01 0a5: 00 0a6: 00 0a7: 00 -0a8: 06 -0a9: 00 +0a8: 255 +0a9: 127 0aa: 00 0ab: 00 -0ac: 00 -0ad: 00 +0ac: 254 +0ad: 255 0ae: 00 0af: 00 -0b0: 01 -0b1: 00 +0b0: 255 +0b1: 255 0b2: 00 0b3: 00 -0b4: 255 -0b5: 127 -0b6: 00 -0b7: 00 -0b8: 254 -0b9: 255 -0ba: 00 -0bb: 00 -0bc: 255 -0bd: 255 -0be: 00 -0bf: 00 -0c0: PCPLUS [40], 16 -0c4: SUBC [32], 4 -0c8: STORE [[32]], [40] -0cc: JMP 168, 1 -0d0: PCPLUS [40], 16 -0d4: SUBC [32], 4 -0d8: STORE [[32]], [40] -0dc: JMP 56, 1 -0e0: PCPLUS [40], 16 -0e4: SUBC [32], 4 -0e8: STORE [[32]], [40] -0ec: JMP 60, 2 -0f0: JMP 192, 0 -0f4: PCPLUS [40], 16 -0f8: SUBC [32], 4 -0fc: STORE [[32]], [40] -100: JMP 24, 1 -104: PCPLUS [40], 16 -108: SUBC [32], 4 -10c: STORE [[32]], [40] -110: JMP 168, 1 -114: JMP 244, 0 -118: CMPC [172], 0 -11c: JNZ 40, 1 -120: XORC [176], 1 -124: MOVC [172], 15 -128: SUBC [172], 1 -12c: LOAD [40], [[32]] -130: ADDC [32], 4 -134: JMPM [40], [0] -138: IN [0], 1 -13c: MOVC [4], 1 -140: AND [4], [0] -144: JZ 84, 1 -148: CMPC [144], 0 -14c: JZ 84, 1 -150: SUBC [144], 1 -154: MOVC [4], 2 -158: AND [4], [0] -15c: JZ 108, 1 -160: CMPC [144], 5 -164: JZ 108, 1 -168: ADDC [144], 1 -16c: MOVC [4], 4 -170: AND [4], [0] -174: JZ 132, 1 -178: CMPC [148], 0 -17c: JZ 132, 1 -180: SUBC [148], 1 -184: MOVC [4], 8 -188: AND [4], [0] -18c: JZ 156, 1 -190: CMPC [148], 5 -194: JZ 156, 1 -198: ADDC [148], 1 -19c: LOAD [40], [[32]] -1a0: ADDC [32], 4 -1a4: JMPM [40], [0] -1a8: CMPC [176], 0 -1ac: JZ 248, 1 -1b0: MOV [0], [180] -1b4: MOVC [4], 7 -1b8: SHL [4], [144] -1bc: OUT 6, [0] +0b4: PCPLUS [40], 16 +0b8: SUBC [32], 4 +0bc: STORE [[32]], [40] +0c0: JMP 156, 1 +0c4: PCPLUS [40], 16 +0c8: SUBC [32], 4 +0cc: STORE [[32]], [40] +0d0: JMP 44, 1 +0d4: PCPLUS [40], 16 +0d8: SUBC [32], 4 +0dc: STORE [[32]], [40] +0e0: JMP 48, 2 +0e4: JMP 180, 0 +0e8: PCPLUS [40], 16 +0ec: SUBC [32], 4 +0f0: STORE [[32]], [40] +0f4: JMP 12, 1 +0f8: PCPLUS [40], 16 +0fc: SUBC [32], 4 +100: STORE [[32]], [40] +104: JMP 156, 1 +108: JMP 232, 0 +10c: CMPC [160], 0 +110: JNZ 28, 1 +114: XORC [164], 1 +118: MOVC [160], 15 +11c: SUBC [160], 1 +120: LOAD [40], [[32]] +124: ADDC [32], 4 +128: JMPM [40], [0] +12c: IN [0], 1 +130: MOVC [4], 1 +134: AND [4], [0] +138: JZ 72, 1 +13c: CMPC [132], 0 +140: JZ 72, 1 +144: SUBC [132], 1 +148: MOVC [4], 2 +14c: AND [4], [0] +150: JZ 96, 1 +154: CMPC [132], 5 +158: JZ 96, 1 +15c: ADDC [132], 1 +160: MOVC [4], 4 +164: AND [4], [0] +168: JZ 120, 1 +16c: CMPC [136], 0 +170: JZ 120, 1 +174: SUBC [136], 1 +178: MOVC [4], 8 +17c: AND [4], [0] +180: JZ 144, 1 +184: CMPC [136], 5 +188: JZ 144, 1 +18c: ADDC [136], 1 +190: LOAD [40], [[32]] +194: ADDC [32], 4 +198: JMPM [40], [0] +19c: CMPC [164], 0 +1a0: JZ 236, 1 +1a4: MOV [0], [168] +1a8: MOVC [4], 7 +1ac: SHL [4], [132] +1b0: OUT 6, [0] +1b4: OUT 7, [4] +1b8: MOVC [4], 0 +1bc: MOV [0], [176] 1c0: OUT 7, [4] -1c4: MOVC [4], 0 -1c8: MOV [0], [188] -1cc: OUT 7, [4] -1d0: OUT 6, [0] -1d4: MOV [0], [184] -1d8: MOVC [4], 7 -1dc: SHL [4], [148] -1e0: OUT 6, [0] +1c4: OUT 6, [0] +1c8: MOV [0], [172] +1cc: MOVC [4], 7 +1d0: SHL [4], [136] +1d4: OUT 6, [0] +1d8: OUT 7, [4] +1dc: MOVC [4], 0 +1e0: MOV [0], [176] 1e4: OUT 7, [4] -1e8: MOVC [4], 0 -1ec: MOV [0], [188] -1f0: OUT 7, [4] -1f4: OUT 6, [0] -1f8: MOV [0], [152] -1fc: MOVC [4], 128 -200: SHLC [4], 8 -204: SHR [4], [0] -208: XOR [4], [160] -20c: MOV [0], [156] -210: MOVC [8], 1 -214: SHL [8], [0] -218: OUT 6, [4] +1e8: OUT 6, [0] +1ec: MOV [0], [140] +1f0: MOVC [4], 128 +1f4: SHLC [4], 8 +1f8: SHR [4], [0] +1fc: XOR [4], [148] +200: MOV [0], [144] +204: MOVC [8], 1 +208: SHL [8], [0] +20c: OUT 6, [4] +210: OUT 7, [8] +214: MOVC [8], 0 +218: MOV [4], [176] 21c: OUT 7, [8] -220: MOVC [8], 0 -224: MOV [4], [188] -228: OUT 7, [8] -22c: OUT 6, [4] -230: LOAD [40], [[32]] -234: ADDC [32], 4 -238: JMPM [40], [0] -23c: CMPC [164], 0 -240: JNZ 88, 2 -244: MOVC [164], 3 -248: PCPLUS [40], 16 -24c: SUBC [32], 4 -250: STORE [[32]], [40] -254: JMP 104, 2 -258: SUBC [164], 1 -25c: LOAD [40], [[32]] -260: ADDC [32], 4 -264: JMPM [40], [0] -268: CMPC [152], 14 -26c: JZ 204, 2 -270: CMPC [152], 1 -274: JZ 240, 2 -278: CMPC [156], 7 -27c: JZ 128, 3 -280: CMPC [156], 0 -284: JZ 128, 3 -288: MOV [0], [168] -28c: ANDC [0], 1 -290: JZ 156, 2 -294: ADDC [152], 1 -298: JMP 160, 2 -29c: SUBC [152], 1 -2a0: MOV [0], [168] -2a4: ANDC [0], 4 -2a8: JZ 176, 2 -2ac: SUBC [156], 1 -2b0: MOV [0], [168] -2b4: ANDC [0], 8 -2b8: JZ 192, 2 -2bc: ADDC [156], 1 -2c0: LOAD [40], [[32]] -2c4: ADDC [32], 4 -2c8: JMPM [40], [0] +220: OUT 6, [4] +224: LOAD [40], [[32]] +228: ADDC [32], 4 +22c: JMPM [40], [0] +230: CMPC [152], 0 +234: JNZ 76, 2 +238: MOVC [152], 3 +23c: PCPLUS [40], 16 +240: SUBC [32], 4 +244: STORE [[32]], [40] +248: JMP 92, 2 +24c: SUBC [152], 1 +250: LOAD [40], [[32]] +254: ADDC [32], 4 +258: JMPM [40], [0] +25c: CMPC [140], 14 +260: JZ 192, 2 +264: CMPC [140], 1 +268: JZ 228, 2 +26c: CMPC [144], 7 +270: JZ 116, 3 +274: CMPC [144], 0 +278: JZ 116, 3 +27c: MOV [0], [156] +280: ANDC [0], 1 +284: JZ 144, 2 +288: ADDC [140], 1 +28c: JMP 148, 2 +290: SUBC [140], 1 +294: MOV [0], [156] +298: ANDC [0], 4 +29c: JZ 164, 2 +2a0: SUBC [144], 1 +2a4: MOV [0], [156] +2a8: ANDC [0], 8 +2ac: JZ 180, 2 +2b0: ADDC [144], 1 +2b4: LOAD [40], [[32]] +2b8: ADDC [32], 4 +2bc: JMPM [40], [0] +2c0: SUBC [32], 4 +2c4: STORE [[32]], [136] +2c8: PCPLUS [40], 16 2cc: SUBC [32], 4 -2d0: STORE [[32]], [148] -2d4: PCPLUS [40], 16 -2d8: SUBC [32], 4 -2dc: STORE [[32]], [40] -2e0: JMP 20, 3 -2e4: LOAD [28], [[32]] -2e8: ADDC [32], 4 -2ec: JMP 120, 2 +2d0: STORE [[32]], [40] +2d4: JMP 8, 3 +2d8: LOAD [28], [[32]] +2dc: ADDC [32], 4 +2e0: JMP 108, 2 +2e4: SUBC [32], 4 +2e8: STORE [[32]], [132] +2ec: PCPLUS [40], 16 2f0: SUBC [32], 4 -2f4: STORE [[32]], [144] -2f8: PCPLUS [40], 16 -2fc: SUBC [32], 4 -300: STORE [[32]], [40] -304: JMP 20, 3 -308: LOAD [28], [[32]] -30c: ADDC [32], 4 -310: JMP 120, 2 -314: MOV [36], [32] -318: ADDC [36], 4 -31c: LOAD [4], [[36]] -320: XORC [168], 3 -324: MOVC [0], 12 -328: XORC [0], 255 -32c: AND [168], [0] -330: CMP [156], [4] -334: JZ 84, 3 +2f4: STORE [[32]], [40] +2f8: JMP 8, 3 +2fc: LOAD [28], [[32]] +300: ADDC [32], 4 +304: JMP 108, 2 +308: MOV [36], [32] +30c: ADDC [36], 4 +310: LOAD [4], [[36]] +314: XORC [156], 3 +318: MOVC [0], 12 +31c: XORC [0], 255 +320: AND [156], [0] +324: CMP [144], [4] +328: JZ 72, 3 +32c: ADDC [4], 1 +330: CMP [144], [4] +334: JZ 104, 3 338: ADDC [4], 1 -33c: CMP [156], [4] -340: JZ 116, 3 -344: ADDC [4], 1 -348: CMP [156], [4] -34c: JZ 100, 3 -350: JMP 244, 0 -354: ORC [168], 4 -358: LOAD [40], [[32]] -35c: ADDC [32], 4 -360: JMPM [40], [0] -364: ORC [168], 8 +33c: CMP [144], [4] +340: JZ 88, 3 +344: JMP 232, 0 +348: ORC [156], 4 +34c: LOAD [40], [[32]] +350: ADDC [32], 4 +354: JMPM [40], [0] +358: ORC [156], 8 +35c: LOAD [40], [[32]] +360: ADDC [32], 4 +364: JMPM [40], [0] 368: LOAD [40], [[32]] 36c: ADDC [32], 4 370: JMPM [40], [0] -374: LOAD [40], [[32]] -378: ADDC [32], 4 -37c: JMPM [40], [0] -380: MOV [0], [168] -384: ANDC [0], 12 -388: JZ 136, 2 -38c: XORC [168], 12 -390: JMP 136, 2 +374: MOV [0], [156] +378: ANDC [0], 12 +37c: JZ 124, 2 +380: XORC [156], 12 +384: JMP 124, 2 diff --git a/planner/__main__.py b/planner/__main__.py index d363b10..5f8fc21 100644 --- a/planner/__main__.py +++ b/planner/__main__.py @@ -5,7 +5,7 @@ from planner.asm import program_parser from planner.sim import bin_parser from planner.sim import devices -from planner.sim.programs import ping_pong +from planner.sim.programs import ping_pong, verilog_input def args_parser(): @@ -26,6 +26,8 @@ def args_parser(): bin_parser = subparsers.add_parser("compile_and_execute") bin_parser.add_argument("program") + + subparsers.add_parser("verilog_io") return parser def main(): @@ -45,6 +47,8 @@ def main(): _bin.set_output_device(6, devices.IntegerOutput("Screen6", bits=16)) while True: _bin.step() + if args.source == "verilog_io": + verilog_input.start() if args.source == "compile_and_execute": if args.program == "ping_pong": ping_pong.start() diff --git a/planner/instruction.py b/planner/instruction.py index efc33a1..c830232 100644 --- a/planner/instruction.py +++ b/planner/instruction.py @@ -51,14 +51,14 @@ class MBlockSelector_stage2(Enum): ''' bits: [read_ram(vrw_source) else read_ram(vr_value)] ''' - VRW_SOURCE_CONST = 0 - VRW_SOURCE_RAM = 1 - VR_VALUE_RAM = 2 + VRW_SOURCE_CONST = 4 + VRW_SOURCE_RAM = 0 + VR_VALUE_RAM = 1 # vr_source<<8 | vrw_source # Pretty specific operation for passing 16-bit constant or address - VR_SOURCE_SHL8_VRW_SOURCE_RAM = 3 - VR_SOURCE_SHL8_VRW_SOURCE_CONST = 4 - PC = 5 + VR_SOURCE_SHL8_VRW_SOURCE_RAM = 2 + VR_SOURCE_SHL8_VRW_SOURCE_CONST = 6 + PC = 7 # last one for reverse lookup DONT_CARE = 0 diff --git a/planner/memory.py b/planner/memory.py index b1706d6..5ef10db 100644 --- a/planner/memory.py +++ b/planner/memory.py @@ -17,8 +17,9 @@ def get_register_address(index): # free # boot sequence -BOOTSEQUENCE_LOAD = 0x30 -BOOTSEQUENCE_ORG = 0x34 # as we have 4-byte rom size header at top +# TODO: We can overlap PROGRAM_ORG and BOOTSEQUENCE_LOAD now +BOOTSEQUENCE_LOAD = 0x40 +BOOTSEQUENCE_ORG = 0x44 # as we have 4-byte rom size header at top # user program DEFAULT_PROGRAM_ORG = 0x80 diff --git a/planner/sim/bin_parser.py b/planner/sim/bin_parser.py index 6ca5e05..5b706ef 100644 --- a/planner/sim/bin_parser.py +++ b/planner/sim/bin_parser.py @@ -12,7 +12,9 @@ def binary_array_num(arr: List[int]): return sum([x<<(8*i) for i, x in enumerate(arr)]) +FLAGS_BITS = 2 FLAGS_BIT_VW_ZERO = 0 +FLAGS_BIT_EXECUTE_FROM_RAM = 1 class BinRunner: def __init__(self, clock: devices.Clock, ram: devices.RAM, brom: devices.ROM): @@ -29,7 +31,7 @@ def __init__(self, clock: devices.Clock, ram: devices.RAM, brom: devices.ROM): # self.is_powered_on = False # self.step() self.is_powered_on = True - self.flags = [0] + self.flags = [0]*FLAGS_BITS # self.step() self.stage = 0 @@ -102,10 +104,10 @@ def m_fetch_and_store_stage2( return binary_array_num(self.read_ram(vr_value, 4)) # reading from 32-bit address if sel == instruction.MBlockSelector_stage2.VRW_SOURCE_RAM: return binary_array_num(self.read_ram(vrw_source, 4)) # reading from 8-bit address - if sel == instruction.MBlockSelector_stage2.VRW_SOURCE_CONST: - return vrw_source if sel == instruction.MBlockSelector_stage2.VR_SOURCE_SHL8_VRW_SOURCE_RAM: return binary_array_num(self.read_ram((vr_source<<8) | vrw_source, 4)) # reading from 16-bit address + if sel == instruction.MBlockSelector_stage2.VRW_SOURCE_CONST: + return vrw_source if sel == instruction.MBlockSelector_stage2.VR_SOURCE_SHL8_VRW_SOURCE_CONST: return (vr_source<<8) | vrw_source if sel == instruction.MBlockSelector_stage2.PC: @@ -132,6 +134,7 @@ def m_fetch_and_store_stage3( return if sel == instruction.MBlockSelector_stage3.PC_NEXT: self.reg_pc_next = vw_value + self.flags[FLAGS_BIT_EXECUTE_FROM_RAM] = 1 return if sel == instruction.MBlockSelector_stage3.PC_NEXT_IF_ZERO: # check previous vw_value flags @@ -146,6 +149,7 @@ def m_fetch_and_store_stage3( if sel == instruction.MBlockSelector_stage3.HLT: self.is_powered_on = False return + raise Exception(f"unsupported selector: {sel}") def m_alu(self, rw: int, r: int, op: instruction.ALU): @@ -156,9 +160,6 @@ def m_alu(self, rw: int, r: int, op: instruction.ALU): def is_power_on(self): return self.is_powered_on - def is_boot_sequence(self): - return self.pc >= memory.BOOTSEQUENCE_ORG and self.pc < memory.DEFAULT_PROGRAM_ORG - def print_bootsequence_completed(self): if hasattr(self, "_print_bootsequence_completed"): return @@ -172,13 +173,12 @@ def trigger_stage0(self): logging.debug("[stage0] PC: 0x%x, flags: %s", self.pc, self.flags) # Read instruction - if self.is_boot_sequence(): + if self.flags[FLAGS_BIT_EXECUTE_FROM_RAM] == 0: brom_address = self.pc-memory.BOOTSEQUENCE_LOAD self.brom.address_line.update(brom_address) ins_binary = self.brom.value_line.get() else: self.print_bootsequence_completed() - self.ram.is_write.update(0) self.ram.address_line.update(self.pc) ins_binary = self.ram.value_out_line.get() ins_binary_array = util.to_little_32binaryarray(ins_binary) @@ -249,6 +249,6 @@ def trigger_stage3(self): self.reg_vrw_source, self.reg_mblock_s3) + # TODO: Move it to stage2 self.flags[FLAGS_BIT_VW_ZERO] = 1 if (self.reg_vw_value==0) else 0 - diff --git a/planner/sim/devices.py b/planner/sim/devices.py index 39ef8d8..0333298 100644 --- a/planner/sim/devices.py +++ b/planner/sim/devices.py @@ -4,6 +4,7 @@ import time import random import logging +import atexit class Device: def __init__(self, bits = 8): @@ -247,7 +248,7 @@ def display(self, only_if_changed=True): if self.use_print: print(new_display) -RAM_SIZE = 0x10000 # 64KB +RAM_SIZE = 0x400 # 4KB class RAM(object): def __init__(self): @@ -262,10 +263,19 @@ def __init__(self): self.is_write = IntegerOutput("ram_is_write", bits=1) self.value_in_line = IntegerOutput("ram_value_in", bits=self.value_bits) self.value_out_line = LatchInput("ram_value_out", bits=self.value_bits) + self._debug_address_used = set() + + def _debug_on_exit(): + print("RAM used: %d byte(s)" % len(self._debug_address_used)) + atexit.register(_debug_on_exit) def _on_address_change(_, __): address = self.address_line.get() value=util.from_littlearray_32binary(self.read_ram(address, 4)) + self._debug_address_used.add(value) + self._debug_address_used.add(value+1) + self._debug_address_used.add(value+2) + self._debug_address_used.add(value+3) self.value_out_line.update(value) self.address_line.add_change_handler(_on_address_change) diff --git a/planner/sim/programs/verilog_input.py b/planner/sim/programs/verilog_input.py new file mode 100644 index 0000000..5d87d2b --- /dev/null +++ b/planner/sim/programs/verilog_input.py @@ -0,0 +1,23 @@ +from planner.sim import verilog_devices, gui_devices +from planner.sim import devices, gui_devices +import pygame + +def start(): + io = verilog_devices.VerilogIO() + gui_manager = gui_devices.GUIDeviceManager() + + input = devices.LatchInput("input", bits=4) + gui_manager.add_device((0, 0), gui_devices.KeyPressedInput(input, { + pygame.K_w: 0, + pygame.K_s: 1, + pygame.K_UP: 2, + pygame.K_DOWN: 3, + })) + io.set_input_device(1, input) + + display = devices.LEDDisplay("LED", use_print=False, width_anode=16, height_cathode=8) + gui_manager.add_device((0, 0), gui_devices.GUILed(display)) + io.set_output_device(6, display.get_anodes()[0]) + io.set_output_device(7, display.get_cathodes()[0]) + io.run(blocking=False) + gui_manager.draw_loop() diff --git a/planner/sim/verilog_devices.py b/planner/sim/verilog_devices.py new file mode 100644 index 0000000..77805e1 --- /dev/null +++ b/planner/sim/verilog_devices.py @@ -0,0 +1,57 @@ +from planner.sim import devices +import threading + +IO_DEVICES = 8 +INPUT_FILE = "/tmp/ourpc_input" + +global_io = None + +def io_loop(): + while True: + s = input() + print(s) + s=s.split() + if s[0]=="IPC": + pid,value = s[1], s[2] + pid=int(pid, 16) + value=int(value, 16) + print("Got PID(%d) Value(%d)" % (pid, value)) + dev = global_io.output_devices[pid] + if dev is None: + print("Device is None") + else: + dev.update(value) + +class VerilogIO: + def __init__(self): + self.input_devices = [None]*IO_DEVICES + self.output_devices = [None]*IO_DEVICES + + global global_io + global_io = self + self.mu = threading.Lock() + self.t = threading.Thread(target=io_loop, args=[]) + + + def run(self, blocking=True): + self.write_input(0, 0) + self.t.start() + if blocking: + self.t.join() + + def write_input(self, new_val, old_val): + data = [0 if i is None else i.get() for i in self.input_devices] + data_str = '\n'.join([ + "{:032b}".format(x) for x in data + ]) + with self.mu: + with open(INPUT_FILE, "w") as f: + f.write(data_str) + + + def set_input_device(self, index: int, d: devices.InputDevice): + d.add_change_handler(self.write_input) + self.input_devices[index] = d + + def set_output_device(self, index: int, d: devices.Device): + self.output_devices[index] = d diff --git a/programs/boot_sequence.asm b/programs/boot_sequence.asm index fcce3a0..8a4b663 100644 --- a/programs/boot_sequence.asm +++ b/programs/boot_sequence.asm @@ -7,7 +7,7 @@ PROM_ADDRESS_LINE equ 2 # input(2) = PROGRAM_ROM value PROM_VALUE_LINE equ 2 -PROGRAM_ORG equ 0x34 +PROGRAM_ORG equ 0x44 RAM_PROGRAM_ORG equ 0x80 ROM_INPUT_VALUE equ 0x0 @@ -25,15 +25,18 @@ section .text movc R1, 4 movc R2, RAM_PROGRAM_ORG copy_more: - cmpc R0, 0 - jz copy_completed out PROM_ADDRESS_LINE, R1 in R3, PROM_VALUE_LINE store [R2], R3 addc R2, 4 addc R1, 4 subc R0, 1 - jmp copy_more + jnz copy_more copy_completed: + # setup default stack + movc ESP, 0x03 + shlc ESP, 8 + orc ESP, 0xFC + # jmp enables FLAGS_BIT_EXECUTE_FROM_RAM jmp RAM_PROGRAM_ORG diff --git a/programs/ping_pong.asm b/programs/ping_pong.asm index 1269cb7..cb22f7c 100644 --- a/programs/ping_pong.asm +++ b/programs/ping_pong.asm @@ -49,9 +49,6 @@ BALL_MINY equ 0 section .text main: - movc ESP, 0xFF - shlc ESP, 8 - orc ESP, 0xF0 jmp game section .data