control bus signals: control bus: register_write register_read pc_write(3) pc_read compare_latch alu_a_write alu_b_write alu_o_read alu_select(4) mem_data_read mem_data_write mem_enable mem_rw mem_address_write mem_address_inc ir_write immediate_select(3) immediate_enable memory_latch_enable memory_latch_select(3) memory_select_select(2) control store bit positions: register_write 0000-0000 0000-0000 0000-0000 0000-0010 register_read 0000-0000 0000-0000 0000-0000 0000-0100 pc_write(3) 0000-0000 0000-0000 0000-0000 00xx-x000 never 0000-0000 0000-0000 0000-0000 0000-0000 always 0000-0000 0000-0000 0000-0000 0000-1000 eq 0000-0000 0000-0000 0000-0000 0001-0000 lt 0000-0000 0000-0000 0000-0000 0001-1000 ltu 0000-0000 0000-0000 0000-0000 0010-0000 ne 0000-0000 0000-0000 0000-0000 0010-1000 ge 0000-0000 0000-0000 0000-0000 0011-0000 geu 0000-0000 0000-0000 0000-0000 0011-1000 pc_read 0000-0000 0000-0000 0000-0000 0100-0000 compare_latch 0000-0000 0000-0000 0000-0000 1000-0000 alu_a_write 0000-0000 0000-0000 0000-0001 0000-0000 alu_b_write 0000-0000 0000-0000 0000-0010 0000-0000 alu_o_read 0000-0000 0000-0000 0000-0100 0000-0000 alu_select(4) 0000-0000 0000-0000 0xxx-x000 0000-0000 add4 0000-0000 0000-0000 0000-0000 0000-0000 add 0000-0000 0000-0000 0000-1000 0000-0000 sub 0000-0000 0000-0000 0001-0000 0000-0000 or 0000-0000 0000-0000 0001-1000 0000-0000 and 0000-0000 0000-0000 0010-0000 0000-0000 xor 0000-0000 0000-0000 0010-1000 0000-0000 sll 0000-0000 0000-0000 0011-0000 0000-0000 slr 0000-0000 0000-0000 0011-1000 0000-0000 sar 0000-0000 0000-0000 0100-0000 0000-0000 slt 0000-0000 0000-0000 0100-1000 0000-0000 sltu 0000-0000 0000-0000 0101-0000 0000-0000 mem_data_read 0000-0000 0000-0000 1000-0000 0000-0000 mem_data_write 0000-0000 0000-0001 0000-0000 0000-0000 mem_enable 0000-0000 0000-0010 0000-0000 0000-0000 mem_rw 0000-0000 0000-0100 0000-0000 0000-0000 mem_address_write 0000-0000 0000-1000 0000-0000 0000-0000 mem_address_inc 0000-0000 0001-0000 0000-0000 0000-0000 ir_write 0000-0000 0010-0000 0000-0000 0000-0000 immediate_select(3) 0000-000x xx00-0000 0000-0000 0000-0000 I 0000-0000 0000-0000 0000-0000 0000-0000 S 0000-0000 0100-0000 0000-0000 0000-0000 B 0000-0000 1000-0000 0000-0000 0000-0000 U 0000-0000 1100-0000 0000-0000 0000-0000 J 0000-0001 0000-0000 0000-0000 0000-0000 immediate_enable 0000-0010 0000-0000 0000-0000 0000-0000 memory_latch_enable 0000-0100 0000-0000 0000-0000 0000-0000 memory_latch_select(3) 00xx-x000 0000-0000 0000-0000 0000-0000 dr 0000-0000 0000-0000 0000-0000 0000-0000 cr 0000-1000 0000-0000 0000-0000 0000-0000 br 0001-0000 0000-0000 0000-0000 0000-0000 ar 0001-1000 0000-0000 0000-0000 0000-0000 dw 0010-0000 0000-0000 0000-0000 0000-0000 cw 0010-1000 0000-0000 0000-0000 0000-0000 bw 0011-0000 0000-0000 0000-0000 0000-0000 aw 0011-1000 0000-0000 0000-0000 0000-0000 register_select_select(2) xx00-0000 0000-0000 0000-0000 0000-0000 rs1 0000-0000 0000-0000 0000-0000 0000-0000 rs2 0100-0000 0000-0000 0000-0000 0000-0000 rsd 1000-0000 0000-0000 0000-0000 0000-0000 r0 1100-0000 0000-0000 0000-0000 0000-0000 the control store is split up into 16 word entries. each instruction can be at maximum 16 microinstructions long (not counting the initial fetch) # the first entry in the control store. fetches the instruction at # ip and writes it to the opcode register FETCH: ip -> mem_address edata -> mem_a; read; inc_address; edata -> mem_b; read; inc_address; edata -> mem_c; read; inc_address; edata -> mem_d; read mem_data -> opcode; # pseudo-entry. increments pc and resets microsequencer for next # instruction. most instructions end with this next: ip -> alu_a alu_o -> ip; alu_op(add4) 0 -> opcode LUI: imm(U) -> reg(rsd) next AUIPC: imm(U) -> alu_a pc -> alu_b alu_o -> reg(rsd), pc next JAL: pc -> alu_a imm(J) -> alu_b alu_o -> reg(rsd); alu_op(add4) alu_o -> pc; alu_op(add) 0 -> opcode JALR: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(add4) alu_o -> pc; alu_op(add) 0 -> opcode BEQ: reg(rs1) -> alu_a reg(rs2) -> alu_b; compare_latch pc -> alu_a alu_o -> pc; alu_op(add4) imm(I) -> alu_b alu_o -> pc(beq); alu_op(add) 0 -> opcode BNE: reg(rs1) -> alu_a reg(rs2) -> alu_b; compare_latch pc -> alu_a alu_o -> pc; alu_op(add4) imm(I) -> alu_b alu_o -> pc(bne); alu_op(add) 0 -> opcode BLT: reg(rs1) -> alu_a reg(rs2) -> alu_b; compare_latch pc -> alu_a alu_o -> pc; alu_op(add4) imm(I) -> alu_b alu_o -> pc(blt); alu_op(add) 0 -> opcode BGE: reg(rs1) -> alu_a reg(rs2) -> alu_b; compare_latch pc -> alu_a alu_o -> pc; alu_op(add4) imm(I) -> alu_b alu_o -> pc(bge); alu_op(add) 0 -> opcode BLTU: reg(rs1) -> alu_a reg(rs2) -> alu_b; compare_latch pc -> alu_a alu_o -> pc; alu_op(add4) imm(I) -> alu_b alu_o -> pc(bltu); alu_op(add) 0 -> opcode BGEU: reg(rs1) -> alu_a reg(rs2) -> alu_b; compare_latch pc -> alu_a alu_o -> pc; alu_op(add4) imm(I) -> alu_b alu_o -> pc(bgeu); alu_op(add) 0 -> opcode # NOTE: we need to take care of the high bytes of the memory input # register when reading less than a word. this is done in the # exth and extb functions in the alu for signed loads. we need to # do the same for the unsigned loads as well somehow LB: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> mem_addr; alu_op(add) edata -> mem_a; read; inc_address mem_data -> alu_a alu_o -> reg(rsd); alu_op(extb) next LH: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> mem_addr; alu_op(add) edata -> mem_a; read; inc_address edata -> mem_b; read; inc_address mem_data -> alu_a alu_o -> reg(rsd); alu_op(exth) next LW: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> mem_addr; alu_op(add) edata -> mem_a; read; inc_address edata -> mem_b; read; inc_address edata -> mem_c; read; inc_address edata -> mem_d; read; mem_data -> reg(rsd) next LBU: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> mem_addr; alu_op(add) edata -> mem_a; read; inc_address mem_data -> reg(rsd) next LHU reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> mem_addr; alu_op(add) edata -> mem_a; read; inc_address edata -> mem_b; read; inc_address mem_data -> reg(rsd) next SB: reg(rs1) -> alu_a imm(S) -> alu_b alu_o -> mem_addr; alu_op(add) mem_a -> edata; write next SH: reg(rs1) -> alu_a imm(S) -> alu_b alu_o -> mem_addr; alu_op(add) mem_a -> edata; write; inc_address mem_b -> edata; write next SW: reg(rs1) -> alu_a imm(S) -> alu_b alu_o -> mem_addr; alu_op(add) mem_a -> edata; write; inc_address mem_b -> edata; write; inc_address mem_c -> edata; write; inc_address mem_d -> edata; write next ADDI: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(add) next SLTI: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(slt) next SLTIU: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(sltu) next XORI: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(xor) next ORI: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(or) next ANDI reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(and) next SLLI: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(sll) next SRLI: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(srl) next SRAI: reg(rs1) -> alu_a imm(I) -> alu_b alu_o -> reg(rsd); alu_op(sra) next ADD: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(add) next SUB: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(sub) next SLL: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(sll) next SLT: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(slt) next SLTU: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(sltu) next XOR: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(xor) next SRL: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(srl) next SRA: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(sra) next OR: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(or) next AND: reg(rs1) -> alu_a reg(rs2) -> alu_b alu_o -> reg(rsd); alu_op(and) next