diff --git a/README.md b/README.md index d4d0281..2f45dae 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ # FPGA Computer -8-bit computer modeled after the SAP-1 from the book [Digital Computer +8-bit computer modeled after the Simple-As-Possible computers from the book [Digital Computer Electronics](https://www.goodreads.com/book/show/942643.Digital_Computer_Electronics) by Malvino and Brown. +The SAP-3 is the final iteration of the computer and shares an instruction set with the Intel +8080/8085, minus a few instructions. + * [Blog post about the SAP-1.](https://austinmorlan.com/posts/fpga_computer_sap1/) * [Blog post about the SAP-2.](https://austinmorlan.com/posts/fpga_computer_sap2/) +* [Blog post about the SAP-3.](https://austinmorlan.com/posts/fpga_computer_sap3/) diff --git a/build.sh b/build.sh index 92d28e9..6e816a3 100755 --- a/build.sh +++ b/build.sh @@ -35,6 +35,17 @@ SAP2_MODULES=" SAP2_TOP=$SRC_DIR/sap2/top.v SAP2_TB=$SRC_DIR/sap2/top_tb.v +SAP3_MODULES=" + $SRC_DIR/sap3/alu.v + $SRC_DIR/sap3/clock.v + $SRC_DIR/sap3/controller.v + $SRC_DIR/sap3/ir.v + $SRC_DIR/sap3/memory.v + $SRC_DIR/sap3/reg_file.v" + +SAP3_TOP=$SRC_DIR/sap3/top.v +SAP3_TB=$SRC_DIR/sap3/top_tb.v + if [ -z "$COMMAND" ]; then mkdir -p $BUILD_DIR/sap1 @@ -54,6 +65,15 @@ if [ -z "$COMMAND" ]; then $BIN_DIR/icepack hardware.asc hardware.bin popd > /dev/null + + mkdir -p $BUILD_DIR/sap3 + pushd $BUILD_DIR/sap3 > /dev/null + + $BIN_DIR/yosys -p "synth_ice40 -json hardware.json" $SAP3_MODULES $SAP3_TOP + $BIN_DIR/nextpnr-ice40 --lp8k --package cm81 --json hardware.json --asc hardware.asc --pcf $SRC_DIR/pins.pcf -q + $BIN_DIR/icepack hardware.asc hardware.bin + + popd > /dev/null elif [ "$COMMAND" == "init" ]; then virtualenv .env source .env/bin/activate @@ -70,13 +90,14 @@ elif [ "$COMMAND" == "program" ]; then exit 1 elif [ "$VERSION" == "sap1" ]; then pushd $BUILD_DIR/sap1 > /dev/null - sudo tinyprog -p hardware.bin - popd > /dev/null elif [ "$VERSION" == "sap2" ]; then pushd $BUILD_DIR/sap2 > /dev/null - sudo tinyprog -p hardware.bin - popd > /dev/null + elif [ "$VERSION" == "sap3" ]; then + pushd $BUILD_DIR/sap3 > /dev/null fi + + sudo tinyprog -p hardware.bin + popd > /dev/null elif [ "$COMMAND" == "sim" ]; then if [ -z "$VERSION" ]; then echo "sim needs a version" @@ -101,8 +122,17 @@ elif [ "$COMMAND" == "sim" ]; then popd > /dev/null gtkwave $BUILD_DIR/sap2/top_tb.vcd $BUILD_DIR/sap2/top_tb.gtkw - fi + elif [ "$VERSION" == "sap3" ]; then + mkdir -p $BUILD_DIR/sap3 + pushd $SRC_DIR/sap3 > /dev/null + $BIN_DIR/iverilog -o $BUILD_DIR/sap3/top_tb $SAP3_MODULES $SAP3_TB + $BIN_DIR/vvp $BUILD_DIR/sap3/top_tb + mv top_tb.vcd $BUILD_DIR/sap3 + popd > /dev/null + + gtkwave $BUILD_DIR/sap3/top_tb.vcd $BUILD_DIR/sap3/top_tb.gtkw + fi else echo "Invalid arguments" fi diff --git a/src/sap3/alu.v b/src/sap3/alu.v new file mode 100644 index 0000000..d7f2f95 --- /dev/null +++ b/src/sap3/alu.v @@ -0,0 +1,173 @@ +module alu( + input clk, + input rst, + input cs, + input flags_we, + input a_we, + input a_store, + input a_restore, + input tmp_we, + input[4:0] op, + input[7:0] bus, + output[7:0] flags, + output[7:0] out +); + +reg carry; + +wire flg_c; +wire flg_z; +wire flg_p; +wire flg_s; + +reg[7:0] acc; +reg[7:0] flg; +reg[7:0] act; // Internal +reg[7:0] tmp; // Internal + +localparam FLG_Z = 0; +localparam FLG_C = 1; +localparam FLG_P = 2; +localparam FLG_S = 3; + +localparam OP_ADD = 5'b00000; +localparam OP_ADC = 5'b00001; +localparam OP_SUB = 5'b00010; +localparam OP_SBB = 5'b00011; +localparam OP_ANA = 5'b00100; +localparam OP_XRA = 5'b00101; +localparam OP_ORA = 5'b00110; +localparam OP_CMP = 5'b00111; +localparam OP_RLC = 5'b01000; +localparam OP_RRC = 5'b01001; +localparam OP_RAL = 5'b01010; +localparam OP_RAR = 5'b01011; +localparam OP_DAA = 5'b01100; // Unsupported +localparam OP_CMA = 5'b01101; +localparam OP_STC = 5'b01110; +localparam OP_CMC = 5'b01111; +localparam OP_INR = 5'b10000; +localparam OP_DCR = 5'b10001; + +assign flg_c = (carry == 1'b1); +assign flg_z = (acc[7:0] == 8'b0); +assign flg_s = acc[7]; +assign flg_p = ~^acc[7:0]; + +always @(posedge clk, posedge rst) begin + if (rst) begin + acc <= 8'b0; + act <= 8'b0; + tmp <= 8'b0; + carry <= 1'b0; + end else begin + if (a_we) begin + acc <= bus; + end else if (a_restore) begin + acc <= act; + end else if (cs) begin + case (op) + OP_ADD: begin + {carry, acc} <= acc + tmp; + end + OP_ADC: begin + {carry, acc} <= acc + tmp + flg[FLG_C]; + end + OP_SUB: begin + {carry, acc} <= acc - tmp; + end + OP_SBB: begin + {carry, acc} <= acc - tmp - flg[FLG_C]; + end + OP_ANA: begin + {carry, acc} <= acc & tmp; + end + OP_XRA: begin + {carry, acc} <= acc ^ tmp; + end + OP_ORA: begin + {carry, acc} <= acc | tmp; + end + OP_CMP: begin + act <= acc - tmp; + end + OP_RLC: begin + carry <= acc[7]; + acc <= acc << 1; + end + OP_RRC: begin + carry <= acc[0]; + acc <= acc >> 1; + end + OP_RAL: begin + carry <= acc[7]; + acc <= (acc << 1 | {7'b0, flg[FLG_C]}); + end + OP_RAR: begin + carry <= acc[0]; + acc <= (acc >> 1 | {flg[FLG_C], 7'b0}); + end + OP_CMA: begin + acc <= ~acc; + end + OP_STC: begin + carry <= 1'b1; + end + OP_CMC: begin + carry <= ~flg[FLG_C]; + end + OP_INR: begin + acc <= acc + 1; + end + OP_DCR: begin + acc <= acc - 1; + end + endcase + end + + if (a_store) + act <= acc; + + if (tmp_we) + tmp <= bus; + end +end + +always @(negedge clk, posedge rst) begin + if (rst) begin + flg <= 8'b0; + end else if (flags_we) begin + flg <= bus; + end else begin + if (cs) begin + case (op) + OP_ADD, OP_ADC, OP_SUB, OP_SBB, OP_ANA, OP_XRA, OP_ORA: begin + flg[FLG_C] <= flg_c; + flg[FLG_Z] <= flg_z; + flg[FLG_S] <= flg_s; + flg[FLG_P] <= flg_p; + end + + OP_CMP: begin + flg[FLG_Z] <= (act == 8'b0); + end + + OP_INR, OP_DCR: begin + flg[FLG_Z] <= flg_z; + flg[FLG_S] <= flg_s; + flg[FLG_P] <= flg_p; + end + + OP_RLC, OP_RRC, OP_RAL, OP_RAR, OP_STC, OP_CMC: begin + flg[FLG_C] <= flg_c; + end + endcase + end + end +end + +assign flags = flg; +assign out = acc; + +endmodule + diff --git a/src/sap3/clock.v b/src/sap3/clock.v new file mode 100644 index 0000000..451d6fb --- /dev/null +++ b/src/sap3/clock.v @@ -0,0 +1,9 @@ +module clock( + input hlt, + input clk_in, + output clk_out); + +assign clk_out = (hlt) ? 1'b0 : clk_in; + +endmodule + diff --git a/src/sap3/controller.v b/src/sap3/controller.v new file mode 100644 index 0000000..798b7b8 --- /dev/null +++ b/src/sap3/controller.v @@ -0,0 +1,928 @@ +module controller( + input clk, + input rst, + input[7:0] opcode, + input[7:0] flags, + output[32:0] out +); + +localparam DISPLAY = 32; +localparam HLT = 31; +localparam ALU_CS = 30; +localparam ALU_FLAGS_WE = 29; +localparam ALU_A_WE = 28; +localparam ALU_A_STORE = 27; +localparam ALU_A_RESTORE = 26; +localparam ALU_TMP_WE = 25; +localparam ALU_OP4 = 24; +localparam ALU_OP0 = 20; +localparam ALU_OE = 19; +localparam ALU_FLAGS_OE = 18; +localparam REG_RD_SEL4 = 17; +localparam REG_RD_SEL0 = 13; +localparam REG_WR_SEL4 = 12; +localparam REG_WR_SEL0 = 8; +localparam REG_EXT1 = 7; +localparam REG_EXT0 = 6; +localparam REG_OE = 5; +localparam REG_WE = 4; +localparam MEM_WE = 3; +localparam MEM_MAR_WE = 2; +localparam MEM_OE = 1; +localparam IR_WE = 0; + +localparam REG_INC = 2'b01; +localparam REG_DEC = 2'b10; +localparam REG_INC2 = 2'b11; + +localparam REG_BC = 5'b10000; +localparam REG_BC_B = 5'b00000; +localparam REG_BC_C = 5'b00001; + +localparam REG_DE = 5'b10010; +localparam REG_DE_D = 5'b00010; +localparam REG_DE_E = 5'b00011; + +localparam REG_HL = 5'b10100; +localparam REG_HL_H = 5'b00100; +localparam REG_HL_L = 5'b00101; + +localparam REG_WZ = 5'b10110; +localparam REG_WZ_W = 5'b00110; +localparam REG_WZ_Z = 5'b00111; + +localparam REG_PC = 5'b11000; +localparam REG_PC_P = 5'b01000; +localparam REG_PC_C = 5'b01001; + +localparam REG_SP = 5'b11010; +localparam REG_SP_S = 5'b01010; +localparam REG_SP_P = 5'b01011; + +reg[32:0] ctrl_word; +reg[3:0] stage; +reg stage_rst; + +assign out = ctrl_word; + +always @(negedge clk, posedge rst) begin + if (rst) begin + stage <= 0; + end else begin + if (stage_rst) begin + stage <= 0; + end else begin + stage <= stage + 1; + end + end +end + +always @(*) begin + ctrl_word = 0; + stage_rst = 0; + + if (stage == 0) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 1) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[IR_WE] = 1'b1; + end else if (stage == 2) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else begin + casez (opcode) + // NOP + 8'o000: begin + stage_rst = 1'b1; + end + + // HLT + 8'o166: begin + if (stage == 3) begin + ctrl_word[HLT] = 1'b1; + end + end + + // MOV Rd, M + // opcode[5:3] - Rd + 8'o1?6: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + if (opcode[5:3] == 3'b111) begin + ctrl_word[ALU_A_WE] = 1'b1; + end else begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:3]}; + ctrl_word[REG_WE] = 1'b1; + end + + ctrl_word[MEM_OE] = 1'b1; + stage_rst = 1'b1; + end + end + + // MOV M, Rs + // opcode[2:0] - Rs + 8'o16?: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + if (opcode[2:0] == 3'b111) begin + ctrl_word[ALU_OE] = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[2:0]}; + ctrl_word[REG_OE] = 1'b1; + end + + ctrl_word[MEM_WE] = 1'b1; + stage_rst = 1'b1; + end + end + + // MOV Rd, Rs + // opcode[5:3] - Rd + // opcode[2:0] - Rs + 8'o1??: begin + if (stage == 3) begin + if (opcode[2:0] == 3'b111) begin + ctrl_word[ALU_OE] = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[2:0]}; + ctrl_word[REG_OE] = 1'b1; + end + + if (opcode[5:3] == 3'b111) begin + ctrl_word[ALU_A_WE] = 1'b1; + end else begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:3]}; + ctrl_word[REG_WE] = 1'b1; + end + + stage_rst = 1'b1; + end + end + + // INX, DCX + // opcode[5:4] - 16-bit Register + // opcode[3] - Dec(1) / Inc (0) + 8'o0?3: begin + if (stage == 3) begin + if (opcode[5:4] == 2'b11) + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + else + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b10, opcode[5:4], 1'b0}; + + ctrl_word[REG_EXT1:REG_EXT0] = {opcode[3], ~opcode[3]}; + stage_rst = 1'b1; + end + end + + // INR/DCR M + // opcode[5:3] - Rs + // opcode[0] - INR (0), DCR (1) + 8'o064: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[ALU_A_STORE] = 1'b1; + ctrl_word[ALU_A_WE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = {4'b1000, opcode[0]}; + end else if (stage == 6) begin + ctrl_word[ALU_OE] = 1'b1; + ctrl_word[ALU_A_RESTORE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + stage_rst = 1'b1; + end + end + + // INR/DCR Rs + // opcode[5:3] - Rs + // opcode[0] - INR (0), DCR (1) + 8'o0?4, 8'o0?5: begin + if (stage == 3) begin + if (opcode[5:3] == 3'b111) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = 5'b10000; + stage_rst = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:3]}; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[ALU_A_STORE] = 1'b1; + ctrl_word[ALU_A_WE] = 1'b1; + end + end else if (stage == 4) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = {4'b1000, opcode[0]}; + end else if (stage == 5) begin + ctrl_word[ALU_OE] = 1'b1; + ctrl_word[ALU_A_RESTORE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:3]}; + ctrl_word[REG_WE] = 1'b1; + stage_rst = 1'b1; + end + end + + // Arithmetic/Logic Set 0 (M) + // opcode[5:3] - ALU Op + 8'o2?6: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[ALU_TMP_WE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = {2'b0, opcode[5:3]}; + stage_rst = 1'b1; + end + end + + // Arithmetic/Logic Set 0 + // opcode[2:0] - Rs + // opcode[5:3] - ALU Op + 8'o2??: begin + if (stage == 3) begin + if (opcode[2:0] == 3'b111) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = {2'b0, opcode[5:3]}; + stage_rst = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[2:0]}; + ctrl_word[REG_OE] = 1'b1; + end + + ctrl_word[ALU_TMP_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = {2'b0, opcode[5:3]}; + stage_rst = 1'b1; + end + end + + // Arithmetic/Logic Set 1 + // opcode[5:3] - ALU Op + 8'o0?7: begin + if (stage == 3) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = {2'b01, opcode[5:3]}; + stage_rst = 1'b1; + end + end + + // Arithmetic/Logic Immediate + // opcode[5:3] - ALU Op + 8'o3?6: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[ALU_TMP_WE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = {2'b0, opcode[5:3]}; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + stage_rst = 1'b1; + end + end + + // MVI M, d8 + 8'o066: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, REG_WZ_W}; + ctrl_word[REG_WE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, REG_WZ_W}; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + stage_rst = 1'b1; + end + end + + // MVI Rd, d8 + // opcode[5:3] - Rd + 8'o0?6: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + if (opcode[5:3] == 3'b111) begin + ctrl_word[ALU_A_WE] = 1'b1; + end else begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:3]}; + ctrl_word[REG_WE] = 1'b1; + end + + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + stage_rst = 1'b1; + end + end + + // LXI + // opcode[5:4] - Extended Register + 8'o001, 8'o021, 8'o041, 8'o061: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + end else if (stage == 8) begin + if (opcode[5:4] == 2'b11) + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + else + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b10, opcode[5:4], 1'b0}; + + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[REG_WE] = 1'b1; + end else if (stage == 9) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + stage_rst = 1'b1; + end + end + + // LDA/STA a16 + // opcode[3]: STA (0) / LDA (1) + 8'o062, 8'o072: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 9) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 10) begin + if (opcode[3] == 0) begin + ctrl_word[ALU_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else begin + ctrl_word[ALU_A_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end + + stage_rst = 1'b1; + end + end + + // STAX/LDAX Rs + // opcode[5:4] - Rs + // opcode[3] - STAX (0) / LDAX (1) + 8'o002, 8'o012, 8'o022, 8'o032: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b0}; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + ctrl_word[REG_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b1}; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + ctrl_word[REG_WE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + if (opcode[3] == 1'b0) begin + ctrl_word[ALU_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else begin + ctrl_word[ALU_A_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end + + stage_rst = 1'b1; + end + end + + // SHLD, LHLD + // opcode[3] - SHLD (0) / LHLD (1) + 8'o042, 8'o052: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[MEM_OE] = 1'b1; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 9) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 10) begin + if (opcode[3] == 1'b0) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL_H; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_HL_H; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end + end else if (stage == 11) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 12) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 13) begin + if (opcode[3] == 1'b0) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL_L; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_HL_L; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end + + stage_rst = 1'b1; + end + end + + // DAD + // opcode[5:4] - Extended Register + 8'o011, 8'o031, 8'o051, 8'o071: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL_L; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[ALU_A_STORE] = 1'b1; + ctrl_word[ALU_A_WE] = 1'b1; + end else if (stage == 4) begin + if (opcode[5:4] == 2'b11) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP_P; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b1}; + end + + ctrl_word[REG_OE] = 1'b1; + ctrl_word[ALU_TMP_WE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = 5'b00000; // Add + end else if (stage == 6) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[ALU_OE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL_H; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[ALU_A_WE] = 1'b1; + end else if (stage == 8) begin + if (opcode[5:4] == 2'b11) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP_S; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b0}; + end + + ctrl_word[REG_OE] = 1'b1; + ctrl_word[ALU_TMP_WE] = 1'b1; + end else if (stage == 9) begin + ctrl_word[ALU_CS] = 1'b1; + ctrl_word[ALU_OP4:ALU_OP0] = 5'b00001; // Add w/ Carry + end else if (stage == 10) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[ALU_OE] = 1'b1; + ctrl_word[ALU_A_RESTORE] = 1'b1; + end else if (stage == 11) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_HL; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_OE] = 1'b1; + stage_rst = 1'b1; + end + end + + // JMP + 8'o303: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_OE] = 1'b1; + stage_rst = 1'b1; + end + end + + // Jump Conditional + // opcode[5:4] - flag + // opcode[3] - set (1) / unset (0) + 8'o3?2: begin + if (stage == 3) begin + if (flags[opcode[5:4]] != opcode[3]) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC2; + stage_rst = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end + end else if (stage == 4) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_OE] = 1'b1; + stage_rst = 1'b1; + end + end + + // Call Conditional + // opcode[5:4] - flag + // opcode[3] - set (1) / unset (0) + 8'o3?4: begin + if (stage == 3) begin + if (flags[opcode[5:4]] != opcode[3]) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC2; + stage_rst = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end + end else if (stage == 4) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 9) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC; + end else if (stage == 10) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 11) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC_C; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else if (stage == 12) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC; + end else if (stage == 13) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 14) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC_P; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else if (stage == 15) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_OE] = 1'b1; + stage_rst = 1'b1; + end + end + + // CALL + 8'o315: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 9) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC; + end else if (stage == 10) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 11) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC_C; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else if (stage == 12) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC; + end else if (stage == 13) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 14) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC_P; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_WE] = 1'b1; + end else if (stage == 15) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_OE] = 1'b1; + stage_rst = 1'b1; + end + end + + // Return Conditional + // opcode[5:4] - flag + // opcode[3] - set (1) / unset (0) + 8'o3?0: begin + if (stage == 3) begin + if (flags[opcode[5:4]] != opcode[3]) begin + stage_rst = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end + end else if (stage == 4) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 9) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_OE] = 1'b1; + stage_rst = 1'b1; + end + end + + // RET + 8'o311: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 9) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ; + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_WE] = 1'b1; + ctrl_word[REG_OE] = 1'b1; + stage_rst = 1'b1; + end + end + + // PUSH Rs + // opcode[5:4] - Extended Register + 8'o3?5: begin + if (stage == 3) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC; + end else if (stage == 4) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 5) begin + if (opcode[5:4] == 2'b11) begin // PSW + ctrl_word[ALU_OE] = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b0}; + ctrl_word[REG_OE] = 1'b1; + end + + ctrl_word[MEM_WE] = 1'b1; + end else if (stage == 6) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC; + end else if (stage == 7) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 8) begin + if (opcode[5:4] == 2'b11) begin // PSW + ctrl_word[ALU_FLAGS_OE] = 1'b1; + end else begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b1}; + ctrl_word[REG_OE] = 1'b1; + end + + ctrl_word[MEM_WE] = 1'b1; + stage_rst = 1'b1; + end + end + + // POP Rs + // opcode[5:4] - Extended Register + 8'o301, 8'o321, 8'o341, 8'o361: begin + if (stage == 3) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 4) begin + if (opcode[5:4] == 2'b11) begin // PSW + ctrl_word[ALU_FLAGS_WE] = 1'b1; + end else begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:4], 1'b1}; + ctrl_word[REG_WE] = 1'b1; + end + + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 5) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + end else if (stage == 6) begin + ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP; + ctrl_word[REG_OE] = 1'b1; + ctrl_word[MEM_MAR_WE] = 1'b1; + end else if (stage == 7) begin + if (opcode[5:4] == 2'b11) begin // PSW + ctrl_word[ALU_A_WE] = 1'b1; + end else begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:4], 1'b0}; + ctrl_word[REG_WE] = 1'b1; + end + + ctrl_word[MEM_OE] = 1'b1; + end else if (stage == 8) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + stage_rst = 1'b1; + end + end + + // OUT + 8'o323: begin + if (stage == 3) begin + ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC; + ctrl_word[REG_EXT1:REG_EXT0] = REG_INC; + ctrl_word[DISPLAY] = 1'b1; + stage_rst = 1'b1; + end + end + endcase + end +end + +endmodule + diff --git a/src/sap3/ir.v b/src/sap3/ir.v new file mode 100644 index 0000000..0ab3f8b --- /dev/null +++ b/src/sap3/ir.v @@ -0,0 +1,22 @@ +module ir( + input clk, + input rst, + input we, + input[7:0] bus, + output[7:0] out +); + +reg[7:0] ir; + +always @(posedge clk, posedge rst) begin + if (rst) begin + ir <= 8'b0; + end else if (we) begin + ir <= bus; + end +end + +assign out = ir; + +endmodule + diff --git a/src/sap3/memory.v b/src/sap3/memory.v new file mode 100644 index 0000000..292cc06 --- /dev/null +++ b/src/sap3/memory.v @@ -0,0 +1,32 @@ +module memory( + input clk, + input rst, + input mar_we, + input ram_we, + input[15:0] bus, + output[7:0] out +); + +initial begin + $readmemh("program.bin", ram); +end + +reg[15:0] mar; +reg[7:0] ram[0:255]; + +always @(posedge clk, posedge rst) begin + if (rst) + mar <= 16'b0; + else if (mar_we) + mar <= bus; +end + +always @(posedge clk) begin + if (ram_we) + ram[mar] <= bus[7:0]; +end + +assign out = ram[mar]; + +endmodule + diff --git a/src/sap3/program.bin b/src/sap3/program.bin new file mode 100644 index 0000000..4206a19 --- /dev/null +++ b/src/sap3/program.bin @@ -0,0 +1,32 @@ +31 f0 00 3e 01 06 00 d3 +ff 4f 78 fe 01 79 ca 17 +00 c2 20 00 c3 07 00 1f +fe 01 cc 29 00 c3 07 00 +17 fe 80 cc 2c 00 c3 07 +00 06 00 c9 06 01 c9 76 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 diff --git a/src/sap3/reg_file.v b/src/sap3/reg_file.v new file mode 100644 index 0000000..ba67ee5 --- /dev/null +++ b/src/sap3/reg_file.v @@ -0,0 +1,72 @@ +module reg_file( + input clk, + input rst, + input[4:0] rd_sel, + input[4:0] wr_sel, + input[1:0] ext, + input we, + input[15:0] data_in, + output[15:0] data_out +); + +// 8-bit +// 0 1 +// 0000_ [ B ][ C ] +// 0001_ [ D ][ E ] +// 0010_ [ H ][ L ] +// 0011_ [ W ][ Z ] +// 0100_ [ P ][ C ] +// 0101_ [ S ][ P ] + +// 16-bit (ext) +// +// 10000 [ BC ] +// 10010 [ DE ] +// 10100 [ HL ] +// 10110 [ WZ ] +// 11000 [ PC ] +// 11010 [ SP ] +reg[7:0] data[0:11]; + +reg[15:0] data_out; +wire wr_ext = wr_sel[4]; +wire rd_ext = rd_sel[4]; +wire[3:0] wr_dst = wr_sel[3:0]; +wire[3:0] rd_src = rd_sel[3:0]; + +localparam EXT_INC = 2'b01; +localparam EXT_DEC = 2'b10; +localparam EXT_INC2 = 2'b11; + +always @(posedge clk, posedge rst) begin + if (rst) begin + data[0] <= 8'b0; data[1] <= 8'b0; data[2] <= 8'b0; data[3] <= 8'b0; data[4] <= 8'b0; + data[5] <= 8'b0; data[6] <= 8'b0; data[7] <= 8'b0; data[8] <= 8'b0; data[9] <= 8'b0; + data[10] <= 8'b0; data[11] <= 8'b0; + end else begin + if (ext == EXT_INC) begin + {data[wr_dst], data[wr_dst+1]} <= {data[wr_dst], data[wr_dst+1]} + 1; + end else if (ext == EXT_INC2) begin + {data[wr_dst], data[wr_dst+1]} <= {data[wr_dst], data[wr_dst+1]} + 2; + end else if (ext == EXT_DEC) begin + {data[wr_dst], data[wr_dst+1]} <= {data[wr_dst], data[wr_dst+1]} - 1; + end else if (we) begin + if (wr_ext) begin + {data[wr_dst], data[wr_dst+1]} <= data_in; + end else begin + data[wr_dst] <= data_in[7:0]; + end + end + end +end + +always @(*) begin + if (rd_ext) begin + data_out = {data[rd_src], data[rd_src+1]}; + end else begin + data_out = {8'b0, data[rd_src]}; + end +end + +endmodule + diff --git a/src/sap3/top.v b/src/sap3/top.v new file mode 100644 index 0000000..a78079b --- /dev/null +++ b/src/sap3/top.v @@ -0,0 +1,153 @@ +module top( + input CLK, + input PIN_24, + output PIN_4, + output PIN_5, + output PIN_6, + output PIN_7, + output PIN_8, + output PIN_9, + output PIN_10, + output PIN_11, +); + + +assign rst = PIN_24; +assign {PIN_4, PIN_5, PIN_6, PIN_7, PIN_8, PIN_9, PIN_10, PIN_11} = out; + +reg[7:0] out; +always @(posedge clk, posedge rst) begin + if (rst) begin + out = 8'b0; + end else if (display) begin + out = alu_out; + end +end + +reg[18:0] bus; + +always @(*) begin + bus = 16'b0; + + if (reg_oe) + bus = reg_out; + else if (mem_oe) + bus = {8'b0, mem_out}; + else if (alu_oe) + bus = {8'b0, alu_out}; + else if (alu_flags_oe) + bus = {8'b0, alu_flags}; +end + +reg[23:0] clk_slow; +always @(posedge CLK) begin + clk_slow <= clk_slow + 1; +end + +wire rst; +wire hlt; +wire clk; +clock clock( + .hlt(hlt), + .clk_in(clk_slow[14]), + .clk_out(clk) +); + +wire[4:0] reg_rd_sel; +wire[4:0] reg_wr_sel; +wire[1:0] reg_ext; +wire reg_oe; +wire reg_we; +wire[15:0] reg_out; +reg_file reg_file( + .clk(clk), + .rst(rst), + .rd_sel(reg_rd_sel), + .wr_sel(reg_wr_sel), + .ext(reg_ext), + .we(reg_we), + .data_in(bus), + .data_out(reg_out) +); + +wire mem_mar_we; +wire mem_ram_we; +wire mem_oe; +wire[7:0] mem_out; +memory memory( + .clk(clk), + .rst(rst), + .mar_we(mem_mar_we), + .ram_we(mem_ram_we), + .bus(bus), + .out(mem_out) +); + +wire ir_we; +wire[7:0] ir_out; +ir ir( + .clk(clk), + .rst(rst), + .we(ir_we), + .bus(bus[7:0]), + .out(ir_out) +); + +wire alu_cs; +wire alu_flags_we; +wire alu_a_we; +wire alu_a_store; +wire alu_a_restore; +wire alu_tmp_we; +wire alu_oe; +wire alu_flags_oe; +wire[4:0] alu_op; +wire[7:0] alu_flags; +wire[7:0] alu_out; +alu alu( + .clk(clk), + .rst(rst), + .cs(alu_cs), + .flags_we(alu_flags_we), + .a_we(alu_a_we), + .a_store(alu_a_store), + .a_restore(alu_a_restore), + .tmp_we(alu_tmp_we), + .op(alu_op), + .bus(bus[7:0]), + .flags(alu_flags), + .out(alu_out) +); + +wire display; +controller controller( + .clk(clk), + .rst(rst), + .opcode(ir_out), + .flags(alu_flags), + .out({ + display, + hlt, + alu_cs, + alu_flags_we, + alu_a_we, + alu_a_store, + alu_a_restore, + alu_tmp_we, + alu_op, + alu_oe, + alu_flags_oe, + reg_rd_sel, + reg_wr_sel, + reg_ext, + reg_oe, + reg_we, + mem_ram_we, + mem_mar_we, + mem_oe, + ir_we + }) +); + +endmodule + diff --git a/src/sap3/top_tb.v b/src/sap3/top_tb.v new file mode 100644 index 0000000..5efdcca --- /dev/null +++ b/src/sap3/top_tb.v @@ -0,0 +1,154 @@ +module top_tb(); + + +initial begin + $dumpfile("top_tb.vcd"); + $dumpvars(0, top_tb); + for (i = 0; i < 12; i++) begin + $dumpvars(0, reg_file.data[i]); + end + for (i = 230; i < 256; i++) begin + $dumpvars(0, memory.ram[i]); + end + rst = 1; + #1 rst = 0; +end + +reg clk_in = 0; +integer i; +initial begin + for (i = 0; i < 8096; i++) begin + #1 clk_in = ~clk_in; + end +end + +reg[7:0] out; +always @(posedge clk, posedge rst) begin + if (rst) begin + out = 8'b0; + end else if (display) begin + out = alu_out; + end +end + +reg[15:0] bus; + +always @(*) begin + bus = 16'b0; + + if (reg_oe) + bus = reg_out; + else if (mem_oe) + bus = {8'b0, mem_out}; + else if (alu_oe) + bus = {8'b0, alu_out}; + else if (alu_flags_oe) + bus = {8'b0, alu_flags}; +end + +reg rst; +wire hlt; +wire clk; +clock clock( + .hlt(hlt), + .clk_in(clk_in), + .clk_out(clk) +); + +wire[4:0] reg_rd_sel; +wire[4:0] reg_wr_sel; +wire[1:0] reg_ext; +wire reg_oe; +wire reg_we; +wire[15:0] reg_out; +reg_file reg_file( + .clk(clk), + .rst(rst), + .rd_sel(reg_rd_sel), + .wr_sel(reg_wr_sel), + .ext(reg_ext), + .we(reg_we), + .data_in(bus), + .data_out(reg_out) +); + +wire mem_mar_we; +wire mem_ram_we; +wire mem_oe; +wire[7:0] mem_out; +memory memory( + .clk(clk), + .rst(rst), + .mar_we(mem_mar_we), + .ram_we(mem_ram_we), + .bus(bus), + .out(mem_out) +); + +wire ir_we; +wire[7:0] ir_out; +ir ir( + .clk(clk), + .rst(rst), + .we(ir_we), + .bus(bus[7:0]), + .out(ir_out) +); + +wire alu_cs; +wire alu_flags_we; +wire alu_a_we; +wire alu_a_store; +wire alu_a_restore; +wire alu_tmp_we; +wire alu_oe; +wire alu_flags_oe; +wire[4:0] alu_op; +wire[7:0] alu_flags; +wire[7:0] alu_out; +alu alu( + .clk(clk), + .rst(rst), + .cs(alu_cs), + .flags_we(alu_flags_we), + .a_we(alu_a_we), + .a_store(alu_a_store), + .a_restore(alu_a_restore), + .tmp_we(alu_tmp_we), + .op(alu_op), + .bus(bus[7:0]), + .flags(alu_flags), + .out(alu_out) +); + +controller controller( + .clk(clk), + .rst(rst), + .opcode(ir_out), + .flags(alu_flags), + .out({ + display, + hlt, + alu_cs, + alu_flags_we, + alu_a_we, + alu_a_store, + alu_a_restore, + alu_tmp_we, + alu_op, + alu_oe, + alu_flags_oe, + reg_rd_sel, + reg_wr_sel, + reg_ext, + reg_oe, + reg_we, + mem_ram_we, + mem_mar_we, + mem_oe, + ir_we + }) +); + +endmodule +