-------------------------------------------------------------------------- -------------------------------------------------------------------------- -- File Name : frisc.v -- Author(s) : Paul R. Joslin -- Affiliation : Laboratory for Digital Design Environments -- Department of Electrical & Computer Engineering -- University of Cincinnati -- Date Created : June 1991 -- Introduction : Behavioral description of FRISC, a RISC based -- microprocessor. -- Source : Original description in Hardware C, written by -- Rajesh Gupta, Stanford University. -- -- Modified For Synthesis by Jay(anta) Roy, University of Cincinnati. -- Date Modified : Sept, 91. -- -- Disclaimer : This comes with absolutely no guarantees of any -- kind (just stating the obvious ...) -- -- Acknowledgement : The Distributed Synthesis Systems research at -- the Laboratory for Digital Design Environments, -- University of Cincinnati, is sponsored in part -- by the Defense Advanced Research Projects Agency -- under order number 7056 monitored by the Federal -- Bureau of Investigation under contract number -- J-FBI-89-094. -- -------------------------------------------------------------------------- -------------------------------------------------------------------------- -- necessary types package frisc_types is -- Note that vhdl requires the following, but vss doesn't accept subtype Byte is BIT_VECTOR(0 to 7); subtype Word is BIT_VECTOR(0 to 15); type Memory is array (0 to 127) of Bit_Vector(0 to 15); -- note the "reverse" array ordering; -- this is used because it is what is "natural" in HardwareC. end frisc_types; -- Description: -- -- frisc describes the operation of a simple risc microprocessor. The -- current HardwareC description is adopted from a frisc description -- written in V. -- -- Literature Reference: -- -- J.R. Southard, "MacPitts: An Approach to Silicon Compilation", IEEE -- Computer, 1983 (pp 74-82). -- -- Operation: -- -- on "reset" the processor loads PC and Stack Ptr from memory: -- -- PC <= mem[0] -- SP <= mem[1] -- -- else during normal operation, the processor does the following operation -- until no opcodes are left: -- -- I (instruction Reg) <= mem[PC] -- PC++ -- -- normal opcodes are 1 byte each, while extended opcodes are 2 consecutive -- bytes long. So each instruction fetch can fetch from 2 to 4 -- instructions. -- -- On interrupts (irq), stack data register and accumulator results are -- saved in memory. Interrupt service routine is loaded from address 2. -- -- SP++ -- mem[SP] <= b -- SP++ -- mem[SP] <= a -- b = m -- a = PC -- m = SP + 1 -- PC = mem[2] -- -- Interrupts are serviced following the next rising edge of the clock. -- Once an interrupt is being processed, further interrupt requests are -- disabled. use Work.frisc_types.all; use Work.functions.all; entity frisc is port( -- See the readme file reset : in BIT; -- reset line irq : in BIT; -- interrupt request iack : out BIT; -- interrupt ack clock : in BIT ); -- The HardwareC ports used for monitoring internal state are not -- implemented here, since VHDL has visibility into the chip. -- They are: -- peaki : out Word; -- peakp : out Word; -- peaks : out Word; -- peaka : out Word; -- peakb : out Word; end frisc; architecture behavior of frisc is -- The clock was commented out in the HardwareC description -- I have added it to make the synthesized HW more useful. -- It is assumed that reads/writes are done on the rising -- edge of the clock. -- Paul. procedure decr(reg : inout Word) is begin reg := reg - "0000000000000001"; end decr; procedure incr(reg : inout Word) is begin reg := reg + "0000000000000001"; end incr; begin chips_ahoy: process variable p : Word; -- program counter variable s : Word; -- stack pointer variable m : Word; -- frame pointer variable a : Word; -- accumulator variable b : Word; -- stack data register variable i : Word; -- instruction register variable t : Word; -- temporary buffer variable opcode, extension_code : integer; variable count1, count2 : integer; -- counters for loops -- The memory and address buses are now on chip -- and contained within this process. variable address, data : Word; -- output busses variable rd, wr : BIT; -- output signals variable MEM : Memory; -- the following are defined to ease decoding alias op_code_0 : BIT is i(0); alias op_code_1 : BIT is i(1); alias op_code_2 : BIT is i(2); alias op_code_3 : BIT is i(3); alias extension_code_0 : Bit is i(4); alias extension_code_1 : Bit is i(5); alias extension_code_2 : Bit is i(6); alias extension_code_3 : Bit is i(7); begin if (reset = '1') then -- read mem[0] into PC p := MEM(0); -- read mem[1] into stack pointer s := MEM(1); else if (irq = '1') then -- interrupt request? wait on clock until clock = '1'; -- rising edge incr(s); MEM(bits_to_int(s)) := b; incr(s); b := a; MEM(bits_to_int(s)) := b; b := m; a := p; incr(m); -- load addr of ISR into PC from mem[2] p := MEM(2); -- acknowledge interrupt iack <= '1'; wait for 1 ns; iack <= '0'; end if; -- fetch opcodes from memory i := MEM(bits_to_int(p)); -- increment PC incr(p); -- loop as long as we have a valid opcode while (not (bits_to_int(i) = 0)) loop -- manually convert opcode to integer opcode := 0; if (op_code_0 = '1') then opcode := 8; end if; if (op_code_1 = '1') then opcode := opcode + 4; end if; if (op_code_2 = '1') then opcode := opcode + 2; end if; if (op_code_3 = '1') then opcode := opcode + 1; end if; case (opcode) is when 1 => -- extended opcode -- manually converted extension to integer extension_code := 0; if (extension_code_0 = '1') then extension_code := 8; end if; if (extension_code_1 = '1') then extension_code := extension_code + 4; end if; if (extension_code_2 = '1') then extension_code := extension_code + 2; end if; if (extension_code_3 = '1') then extension_code := extension_code + 1; end if; case(extension_code) is when 0 => -- nand b := not (a and b); a := b; b := MEM(bits_to_int(s)); decr(s); when 1 => -- subtract b := b - a; a := b; b := MEM(bits_to_int(s)); when 2 => -- shift right right_shift(a); when others => -- null ; -- do nothing, since you can't -- fix the error end case; -- shift i right by 4 count1 := 4; while count1 > 0 loop right_shift(i); count1 := count1 - 1; end loop; when 2 => -- constant incr(s); MEM(bits_to_int(s)) := b; b := a; a := MEM(bits_to_int(p)); incr(p); when 3 => -- get S incr(s); MEM(bits_to_int(s)) := b; b := a; a := s; when 4 => -- set S s := a; a := b; b := MEM(bits_to_int(s)); decr(s); when 5 => -- get M incr(s); MEM(bits_to_int(s)) := b; b := a; a := m; when 6 => -- load a := MEM(bits_to_int(s)); when 7 => -- store MEM(bits_to_int(b)) := a; a := b; b := MEM(bits_to_int(s)); decr(s); when 8 => -- go to p := a; a := b; b := MEM(bits_to_int(s)); decr(s); when 9 => -- if if (bits_to_int(b) < 0) then p := a; end if; a := b; b := MEM(bits_to_int(s)); decr(s); when 10 => -- end a := b; b := MEM(bits_to_int(s)); decr(s); when 11 => -- mark incr(s); MEM(bits_to_int(s)) := b; b := a; a := m; m := s + 2; when 12 => -- call t := p; p := a; a := t; when 13 => -- return p := b; b := a; s := m; a := b; b := MEM(bits_to_int(s)); decr(s); m := b; b := a; a := b; b := MEM(bits_to_int(s)); decr(s); when 14 => -- add b := b + a; a := b; b := MEM(bits_to_int(s)); decr(s); when 15 => -- increment a := a + 1; when others => -- null; -- do nothing; ideally you -- would report the error end case; -- shift i right by 4 count1 := 4; while count1 > 0 loop right_shift(i); count1 := count1 - 1; end loop; -- shift i right 4 times end loop; -- while i <> 0 end if; end process ; end behavior;