From 780f056e61323a41abcaf0dd53a44f99bcac197c Mon Sep 17 00:00:00 2001 From: Wojciech Kosior Date: Wed, 16 Sep 2020 14:42:32 +0200 Subject: add function calling (call, ret and drop instructions) with a testbench + bugfix in stack machine --- design/stack_machine.v | 45 +++++++++-- tclasm.tcl | 24 ++++++ tests/stack_machine_function_call/Makefile | 1 + .../stack_machine_function_call/instructions.s.tcl | 88 ++++++++++++++++++++++ tests/stack_machine_function_call/test.v | 1 + .../words_to_verify.mem | 3 + 6 files changed, 155 insertions(+), 7 deletions(-) create mode 120000 tests/stack_machine_function_call/Makefile create mode 100644 tests/stack_machine_function_call/instructions.s.tcl create mode 120000 tests/stack_machine_function_call/test.v create mode 100644 tests/stack_machine_function_call/words_to_verify.mem diff --git a/design/stack_machine.v b/design/stack_machine.v index 54eae5e..91e808b 100644 --- a/design/stack_machine.v +++ b/design/stack_machine.v @@ -206,10 +206,18 @@ module stack_machine_new assign instr_tee = !set_im && !use_im && stack_grows && instruction[11:0] == 12'd0; + wire instr_get_frame; + assign instr_get_frame = !set_im && !use_im && stack_grows && + instruction[11:0] == 12'd1; + wire instr_const; assign instr_const = use_im && stack_grows && instruction[11:7] == 5'd0; + wire instr_call; + assign instr_call = use_im && stack_grows && + instruction[11:7] == 5'd1; + /* Instructions, that shrink stack */ wire instr_add; assign instr_add = !set_im && !use_im && stack_shrinks_by_1 && @@ -227,6 +235,14 @@ module stack_machine_new assign instr_mul = !set_im && !use_im && stack_shrinks_by_1 && instruction[11:0] == 12'd3; + wire instr_drop; + assign instr_drop = !set_im && !use_im && stack_shrinks_by_1 && + instruction[11:0] == 12'd4; + + wire instr_ret; + assign instr_ret = !set_im && !use_im && stack_shrinks_by_1 && + instruction[11:0] == 12'b000010000000; + wire instr_cond_jump; assign instr_cond_jump = use_im && stack_shrinks_by_1 && instruction[11:7] == 5'd1; @@ -366,8 +382,6 @@ module stack_machine_new I_CYC_O <= 1; D_CYC_O <= 0; - D_STB_O <= 0; - D_WE_O <= 0; end if (first_execution_tick) begin @@ -434,8 +448,9 @@ module stack_machine_new <= {stack_transfer_unrequested[0], 1'b0}; end - if (load_store_unrequested || - stack_transfer_unrequested[0]) begin + if (stack_transfer_unrequested[0] || + (load_store_unrequested && + stack_transfer_unrequested[1])) begin if (stack_shrinks) begin `SET_SP(sp + 4); D_ADR_O <= sp; @@ -443,7 +458,7 @@ module stack_machine_new D_SEL_O <= 4'b1111; D_STB_O <= 1; D_WE_O <= 0; - end else if (stack_grows) begin + end else /* if (stack_grows) */ begin `SET_SP(sp - 4); D_ADR_O <= sp - 4; D_DAT_O <= stack_put_value; @@ -451,13 +466,13 @@ module stack_machine_new D_STB_O <= 1; D_WE_O <= 1; end - end else begin // if (load_store_unrequested ||... + end else begin // if (stack_transfer_unrequested[0] ||... D_ADR_O <= 21'bx; D_DAT_O <= 32'bx; D_SEL_O <= 4'bx; D_STB_O <= 0; D_WE_O <= 0; - end // else: !if(load_store_unrequested ||... + end // else: !if(stack_transfer_unrequested[0] ||... end // if (data_request_happens) if (data_command_completes) begin @@ -521,9 +536,17 @@ module stack_machine_new if (instr_tee) r1 <= r1; + if (instr_get_frame && first_execution_tick) + r1 <= sp; + if (instr_const && first_execution_tick) r1 <= im_effective; + if (instr_call && first_execution_tick) begin + r1 <= pc; + `SET_PC(im_effective); + end + /* Instructions, that shrink stack */ if (instr_add && arithmetic_uncompleted) r1 <= r0 + r1; @@ -537,12 +560,20 @@ module stack_machine_new if (instr_mul && arithmetic_uncompleted) r1 <= r0 * r1; + if (instr_drop && arithmetic_uncompleted) + r1 <= r0; + if (instr_cond_jump && arithmetic_uncompleted) begin r1 <= r0; if (r1) `SET_PC(im_effective); end + + if (instr_ret && arithmetic_uncompleted) begin + r1 <= r0; + `SET_PC(r1); + end end // case: STEP_EXECUTING endcase // case (step) end // else: !if(RST_I) diff --git a/tclasm.tcl b/tclasm.tcl index f80863d..0dec4b0 100755 --- a/tclasm.tcl +++ b/tclasm.tcl @@ -273,6 +273,11 @@ proc tee {} { } +proc get_frame {} { + puts 0001000000000001 +} + + proc _const {value_part} { puts 010100000[__to_binary $value_part 7] } @@ -282,6 +287,15 @@ proc const {value} { } +proc _call {address_part} { + puts 010100001[__to_binary $address_part 7] +} + +proc call {address} { + _with_im _call $address +} + + # Instructions, that shrink stack proc add {} { @@ -304,6 +318,16 @@ proc mul {} { } +proc drop {} { + puts 0011000000000100 +} + + +proc ret {} { + puts 0011000010000000 +} + + proc _cond_jump {address_part} { puts 011100001[__to_binary $address_part 7] } diff --git a/tests/stack_machine_function_call/Makefile b/tests/stack_machine_function_call/Makefile new file mode 120000 index 0000000..2c3c770 --- /dev/null +++ b/tests/stack_machine_function_call/Makefile @@ -0,0 +1 @@ +../stack_machine_store/Makefile \ No newline at end of file diff --git a/tests/stack_machine_function_call/instructions.s.tcl b/tests/stack_machine_function_call/instructions.s.tcl new file mode 100644 index 0000000..450b669 --- /dev/null +++ b/tests/stack_machine_function_call/instructions.s.tcl @@ -0,0 +1,88 @@ +### call a simple function, that sums its 2 arguments + +## store sth at h1000 to later check if calee restored it properly +# 1 16-bit instruction +const h23 +# 2 16-bit instructions +store h1000 + +# function arguments - each loaded with 1 16-bit instruction +const h32 +const h14 +# also 1 16-bit instruction +call 18 + +## this executes after return - store the computed difference at h400 +# this takes 2 16-bit instructions +store h400 +# and this takes 1 16-bit instruction +halt + +# address 18 here + +## function frame will look like this: +## *****higher addresses***** +## argument1 +## argument2 +## ... +## return address +## local1 +## local2 +## ... +## previous frame address +## *****lower addresses***** + +## push the arguments out of r0 and r1 to memory (+ claim space for +## backed stack frame address and backed return address); +## if we had n local variables, we'd repeat that n more times +const 0 +const 0 +const 0 + +## with this we get the address to reference our locals from into r1 +get_frame +tee + +## we get our previous frame and back it up as first local +load h1000 +store+ h0 + +## we now store our new function frame +store h1000 + +## here the actual function body starts + +## fetch the first argument +load h1000 +load+ hC + +## fetch the second one +load h1000 +load+ h8 + +sub + +## function exit - store the result at the the top of current frame +load h1000 +swap +store+ hC + +## put the return address just below result +load h1000 +tee +tee +load+ h4 +store+ h8 + +## restore old frame +load+ 0 +store h1000 + +## discard current frame +drop +drop +drop +drop + +## return +ret diff --git a/tests/stack_machine_function_call/test.v b/tests/stack_machine_function_call/test.v new file mode 120000 index 0000000..f5b6a59 --- /dev/null +++ b/tests/stack_machine_function_call/test.v @@ -0,0 +1 @@ +../stack_machine_store/test.v \ No newline at end of file diff --git a/tests/stack_machine_function_call/words_to_verify.mem b/tests/stack_machine_function_call/words_to_verify.mem new file mode 100644 index 0000000..8048d6f --- /dev/null +++ b/tests/stack_machine_function_call/words_to_verify.mem @@ -0,0 +1,3 @@ +// address value + 1000 23 + 400 1E -- cgit v1.2.3