/* 18 - 36 bit mini microprocessor data bus : 18 bit registers : A & B (36 bit), PC (max 15 bit) Data Memory Address (max 12 bit) instruction & machine code : type instruction = INA of io_address (* input a value from IO of io_address to reg A *) | OUTA of io_address (* output reg A value to IO of io_address *) | INAM of io_address (* input a value from IO of the address value at io_address to reg A *) | OUTAM of io_address (* output reg A value to IO of the address value at io_address *) | LDAI of int * word_count (* load an immediate value to reg A *) | LDBI of int * word_count (* load an immediate value to reg B *) | LDAM of d_address * low_high (* load a value in the data memory at d_address to reg A *) | LDBM of d_address * low_high (* load a value in the data memory at d address to reg B *) | STAM of d_address * low_high (* store the value in reg A to the data memory at d_address *) | STBM of d_address * low_high (* store the value in reg B to the data memory at d_address *) | LDAMM of d_address * low_high (* load a value in the data memory at the address value at d_address to reg A *) | STAMM of d_address * low_high (* store the value in reg A to the data memory at the address value at d_address *) | NOT (* reg A <- not reg A *) | ADD (* reg A <- reg A + reg B *) | SUB (* reg A <- reg A - reg B *) | MUL of word_count (* reg A <- reg A * reg B *) | LSH (* left shift of reg A for reg B times *) | ARSH of word_count (* arithmetic right shift of reg A for reg B times *) | RSH of word_count (* right shift of reg A for reg B times *) | LT_UNS of word_count (* bit 0 of reg A <- (reg A < reg B) (unsigned) *) | LT_SGN of word_count (* bit 0 of reg A <- (reg A < reg B) (signed) *) | LE_UNS of word_count (* bit 0 of reg A <- (reg A <= reg B) (unsigned) *) | LE_SGN of word_count (* bit 0 of reg A <- (reg A <= reg B) (signed) *) | EQ of word_count (* bit 0 of reg A <- (reg A = reg B) *) | AND (* reg A <- reg A and reg B *) | OR (* reg A <- reg A or reg B *) | XOR (* reg A <- reg A xor reg B *) | SGN_EXT (* reg A <- sign extension of reg A(17..0) *) | UNS_EXT (* reg A <- unsign extension of regA(17..0) *) | JP of symid (* jump (actually microcontroller doesn't have this instruction) *) | JP_C of symid (* jump if bit 0 of reg A = 1 ( actually microcontroller doesn't have this instruction) *) | JP_CN of symid (* jump if bit 0 of reg A = 0 ( actually microcontroller doesn't have this instruction) *) | JR of r_address (* relative jump *) | JR_C of r_address (* relative jump if bit 0 of reg A = 1 *) | JR_CN of r_address (* relative jump if bit 0 of reg A = 0 *) let code_length_cycle_of_instruction = function (* code, length, cycle *) INA a -> ([0b001000000000000000 lor a], 1, 2) | OUTA a -> ([0b001010000000000000 lor a], 1, 2) | INAM a -> ([0b001001000000000000 lor a], 1, 4) | OUTAM a -> ([0b001011000000000000 lor a], 1, 4) | LDAI (i, w) -> if w then ([0b000001000000000000; i land 0b111111111111111111; i lsr 18], 3, 3) else ([0b000000000000000000; i], 2, 2) | LDBI (i, w) -> if w then ([0b000101000000000000; i land 0b111111111111111111; i lsr 18], 3, 3) else ([0b000100000000000000; i], 2, 2) | LDAM (a, h) -> ([(if h then 0b010001000000000000 else 0b010000000000000000) lor a], 1, 3) | LDBM (a, h) -> ([(if h then 0b010011000000000000 else 0b010010000000000000) lor a], 1, 3) | STAM (a, h) -> ([(if h then 0b010101000000000000 else 0b010100000000000000) lor a], 1, 3) | STBM (a, h) -> ([(if h then 0b010111000000000000 else 0b010110000000000000) lor a], 1, 3) | LDAMM (a, h) -> ([(if h then 0b011101000000000000 else 0b011100000000000000) lor a], 1, 4) | STAMM (a, h) -> ([(if h then 0b011111000000000000 else 0b011110000000000000) lor a], 1, 4) | NOT -> ([0x0001], 1, 2) | ADD -> ([0x0002], 1, 2) | SUB -> ([0x0003], 1, 2) | MUL w -> ([if w then 0x1004 else 0x0004], 1, 2) | LSH -> ([0x0006], 1, 1 (* + shift count *) ) | ARSH w -> ([if w then 0x1007 else 0x0007], 1, 1 (* + shift count *) ) | RSH w -> ([if w then 0x1008 else 0x0008], 1, 1 (* + shift count *) ) | LT_UNS w -> ([if w then 0x1009 else 0x0009], 1, 2) | LT_SGN w -> ([if w then 0x100a else 0x000a], 1, 2) | LE_UNS w -> ([if w then 0x100b else 0x000b], 1, 2) | LE_SGN w -> ([if w then 0x100c else 0x000c], 1, 2) | EQ w -> ([if w then 0x100d else 0x000d], 1, 2) | AND -> ([0x000e], 1, 2) | OR -> ([0x000f], 1, 2) | XOR -> ([0x0010], 1, 2) | SGN_EXT -> ([0x0011], 1, 2) | UNS_EXT -> ([0x0012], 1, 2) | JP sid -> ([], 1, 2) | JP_C sid -> ([], 1, 2) | JP_CN sid -> ([], 1, 2) | JR a -> ([0b100000000000000000 lor a], 1, 2) | JR_C a -> ([0b101000000000000000 lor a], 1, 2) | JR_CN a -> ([0b110000000000000000 lor a], 1, 2) */ process processor( clkin uint#1 clk, rstin uint#1 rst, ram uint#18 imem0[1024], ram uint#18 dmem0[1024], in uint#18 in_port, out uint#18 latch out_port ) { uint#15 pc = 0; // program counter uint#12 dmadr = 0; // data memory address uint#36 rega = 0, regb = 0; // registers uint#36 temp0 = 0; uint#18 temp1 = 0; uint#18 temp2 = 0; uint#3 op_kind = 0; uint#3 next = 0; // for multi state instruction uint#18 inst = 0; // instruction uint#1 high = 0, highi = 0; uint#2 mul_phase = 0; while (1) { switch (next) { case 0: { // fetch // switch (pc#(14..10)) { /* default: */ inst = imem0[pc#(9..0)]; /* break; */ // } pc++; next = 1; } break; case 1: { // exec if (inst#(17)) { // JP kind instructinons switch (inst#(16..15)) { case 0b00: // JP pc += inst#(14..0); next = 0; break; case 0b01: // JP_C if (rega#(0)) pc += inst#(14..0); next = 0; break; case 0b10: // JP_CN if (~(rega#(0))) pc += inst#(14..0); next = 0; break; default: next = 0; break; } } else if (inst#(17..16)==0b01) { // DMEM kind instructions high = inst#(12); switch (inst#(15..13)) { case 0b000: // LDAM dmadr = inst#(11..0); next = 3; op_kind = 0; break; case 0b001: // LDBM dmadr = inst#(11..0); next = 3; op_kind = 1; break; case 0b010: // STAM dmadr = inst#(11..0); next = 4; op_kind = 0; break; case 0b011: // STBM dmadr = inst#(11..0); op_kind = 1; next = 4; break; case 0b110: // LDAMM dmadr = inst#(11..0); next = 3; op_kind = 0b10; break; case 0b111: // STAMM dmadr = inst#(11..0); next = 3; op_kind = 0b110; break; } } else if (inst#(17..15)==0b001) { // IO kind instructions switch (inst#(14..13)) { case 0b00: { // IN uint#13 io_adr = inst#(12..0); switch (io_adr) { case 0x0: // normal input rega = in_port; next = 0; break; default: next = 0; break; } } break; case 0b01: { // OUT uint#13 io_adr = inst#(12..0); switch (io_adr) { case 0x0: // normal output out_port = rega; next = 0; break; default: next = 0; break; } } break; } } else { // normal instructions switch (inst#(5..0)) { case 0x00: { // LDAI , LDBI uint#18 i; // switch (pc#(14..10)) { /* default: */ i = imem0[pc#(9..0)]; /* break; */ // } pc++; if (inst#(14)) { if (highi) { regb = i @ regb#(17..0); } else { regb = i; } } else { if (highi) { rega = i @ rega#(17..0); } else { rega = i; } } if (inst#(12) & ~highi) { highi = 1; next = 1; } else { highi = 0; next = 0; } } break; case 0x01: // NOT rega = ~rega; next = 0; break; case 0x02: // ADD rega = rega + regb; next = 0; break; case 0x03: // SUB rega = rega - regb; next = 0; break; case 0x04: { // MUL if (inst#(12)) { switch (mul_phase) { case 0: temp0 = (rega#(17..0)*regb#(17..0)); temp1 = (rega#(34..18)*regb#(17..0))#(17..0); temp2 = (rega#(17..0)*regb#(34..18))#(17..0); mul_phase = 1; next = 1; break; default: rega = temp0 + ((temp1 + temp2)@0b000000000000000000); mul_phase = 0; next = 0; break; } } else { rega = (rega#(17..0) * regb#(17..0))#(17..0); next = 0; } } break; case 0x06: // Lsh if (regb != 0) { if (regb#(3)) { rega = rega#(28..0)@0b00000000; regb -= 8; } else { rega = rega#(34..0)@0b0; regb--; } if (regb == 0) next = 0; else next = 1; } else next = 0; break; case 0x07: // ARsh if (regb != 0) { if (inst#(12)) { rega = rega#(35)@rega#(35..1); } else { rega = rega#(17)@rega#(17..1); } regb--; if (regb == 0) next = 0; else next = 1; } else next = 0; break; case 0x08: // Rsh if (regb != 0) { if (regb#(3)) { if (inst#(12)) { rega = 0b00000000@rega#(35..8); } else { rega = 0b00000000@rega#(17..8); } regb -= 8; } else { if (inst#(12)) { rega = 0b0@rega#(35..1); } else { rega = 0b0@rega#(17..1); } regb--; } if (regb == 0) next = 0; else next = 1; } else next = 0; break; case 0x09: { // LtUns uint#36 regaa = inst#(12)?rega:rega#(17..0); uint#36 regbb = inst#(12)?regb:regb#(17..0); rega = (regaa