OpenCores
URL https://opencores.org/ocsvn/risc16f84/risc16f84/trunk

Subversion Repositories risc16f84

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 6 to Rev 7
    Reverse comparison

Rev 6 → Rev 7

/tags/V001/risc16f84_clk2x.v File deleted \ No newline at end of file
/tags/V001/Image4.gif Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
tags/V001/Image4.gif Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: tags/V001/people.shtml =================================================================== --- tags/V001/people.shtml (revision 6) +++ tags/V001/people.shtml (nonexistent) @@ -1,10 +0,0 @@ -Project: memory_sizer

-Overview | -People | -Documentation | -Download | -OpenCores Mail list | -Contact me
-

-The People

-John E. Clayton from Scottsdale, Arizona, USA

Index: tags/V001/download.shtml =================================================================== --- tags/V001/download.shtml (revision 6) +++ tags/V001/download.shtml (nonexistent) @@ -1,24 +0,0 @@ -Project: risc16f84

-Overview | -People | -Documentation | -Download | -OpenCores Mail list | -Contact me
-

Download

-

Allright, here are "the goods!"

- -

Downloads:

-

-

risc16f84_clk2x.v. This file contains the stripped down 16f84 microcontroller: 1 interrupt input, no watch dog timer, no port A and B, plus the Auxiliary bus (which handles much more than Ports A and B), plus it runs at 2 clock cycles per instruction. -

risc16f84_small.v. This file contains the 16f84 Verilog code without EEPROM interface, with only a single interrupt input. -

risc16f84_lite.v. This file contains the 16f84 Verilog code without EEPROM interface. -

risc16f84.v. This file contains the full-blown 16f84 Verilog code. -

-

-b11_risc16f84_05_07_02.zip. -This file contains an example of the risc16f84_clk2x module in use. The top level module is "top.v" It uses tri-state buffers for data buses, except for the Xilinx DPRAM used to implement the 512 byte register file, which has separate data in and data out buses. There is support for hardware breakpoints, single stepping and resetting the processor through "rs232_syscon" commands given through a serial port (see opencores project at rs232_syscon).

-

This entire project fits into a Xilinx XC2S200 chip, taking up only about 950 slices or so, and all 14 of the DPRAM blocks (9 of the DPRAMS for a "pixel" memory for a 128 by 96 pixel display that I implemented with this project. You can remove these from the project, add new registers, create new peripherals -- whatever you like.) -

NOTE: In order to get these examples to work on your own board, you will need to generate a correct BAUD clock on your board -- see the file "serial.v" for details. Also, you will need some "level translating" circuit to change the LVTTL level signals coming out of the Xilinx chip into RS232 levels for connection to your computer's serial port. Be sure to re-assign the IO constraints to match the desired pinouts on your board, and add debug outputs if you like, so that you can view what is happening on a logic analyzer... Or, you could also simulate these modules! -

- Index: tags/V001/b13c_environment.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: tags/V001/b13c_environment.zip =================================================================== --- tags/V001/b13c_environment.zip (revision 6) +++ tags/V001/b13c_environment.zip (nonexistent)
tags/V001/b13c_environment.zip Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: tags/V001/index.shtml =================================================================== --- tags/V001/index.shtml (revision 6) +++ tags/V001/index.shtml (nonexistent) @@ -1,7 +0,0 @@ -Project: risc16f84

-People | -Documentation | -Download | -OpenCores Mail list | -Contact me

Description

The risc16f84 project is intended to provide a small, easy to use microcontroller in Verilog. The original code was VHDL, but I have done a wonderful translation of it into good clean Verilog code. (Well, I think it is wonderful, anyway.) The VHDL code was called "CQPIC" and it was published in 1999 by Sumio Morioka of Japan, in the December 1999 issue of "Transistor Gijutsu Magazine." I did the translation by hand, and then tested the design in actual hardware by running C code on it, and looking for correct behavior. I realize that this is not 100% test coverage, but I have found and fixed several bugs by this method -- including an error in the carry bit logic of the original code! There are four separate versions of the microcontroller presented here. The "original" one is called "risc16f84.v" and it includes all the logic needed to implement the entire 16f84 chip functionality as published in the original article.

However, I have realized over time, that a person using a microcontroller inside of an FPGA does not have the same constraints (i.e. on port sizes, number of pins, multiple functions needed on each pin, etc.) as the original chip designers, and so I have taken liberty in the other three versions, to simplify the logic by removing items that may not be wanted inside of an FPGA or ASIC implementation. For example, there is a version called "risc16f84_lite.v" which has no interface for the EEPROM...

Another version, called "risc16f84_small.v" further eliminates the multiple interrupt sources present on the original chip (since in a PIC there is only one interrupt vector defined, so interrupt service routines must do some "checking" anyway to determine the source of an interrupt - why bother having separate inputs defined? Just make up your own interrupt structure and use it the way you like inside of your chip!)

Finally, the fourth version, called "risc16f84_clk2x.v" further removes the port A and port B interfaces, since you can create as many ports as you like inside of your own chip. Toward this end, "risc16f84_clk2x.v" also includes an "auxiliary" bus interface, allowing the microcontroller to access 64k bytes of registers, ports and hardware peripherals, all defined within their own address space -- not within the limited register space of the PIC microcontrollers. I have used it to address a screen with 12288 pixels, and each pixel has its own address. It is easy to define addresses for the auxiliary bus components in most PIC code generation tools, so this works out nicely.

The code is written in Verilog, and was sythesized into a Xilinx SpartanII XC2S200 chip. Debugging was done in actual hardware, with an HP16500 series logic analyzer, and there are no simulation testbenches for these modules.

-

The design team welcomes any kind of help and feedback on these cores. If you are interested in further development of this project, please contact us.


Current Status:

  • The "risc16f84_clk2x.v" core has been coded completely, synthesized and tested for correct operation (and debugged!) inside a Xilinx XC2S200 chip. The tools used for development were the Xilinx Foundation 3.1i (non-ISE) tools.
  • The original "risc16f84.v" supports execution with 4 clocks per instruction, as in PIC microcontrollers.
  • The "risc16f84_clk2x" version uses only 2 clocks per instruction.
  • The "risc16f84_clk2x.v" core was tested at 49.125 MHz (approx. 25 MIPS), and uses 321 Virtex slices.
  • Xilinx DPRAM blocks were used to implement the processor register space and program ROM. These RAMs are dual-ported, so I have mapped the other port into the "auxiliary bus" space.
  • Debugging is aided by the use of "rs232_syscon.v" which is a hardware "monitor" that allows read/write of addresses on the auxiliary bus.
  • Since the registers and all useful peripherals are present on the auxiliary bus, single stepping and hardware breakpoints are implemented through the rs232_syscon interface (a serial port connects to a terminal window.)
  • I have been downloading C code through the serial port, in the form of rs232_syscon write commands.
  • A PERL script transforms s-record files into rs232_syscon write commands.
  • The cores are parameterized.
  • The code has good comments.

Maintainer(s):

Mailing-list:

\ No newline at end of file Index: trunk/people.shtml =================================================================== --- trunk/people.shtml (revision 6) +++ trunk/people.shtml (nonexistent) @@ -1,10 +0,0 @@ -Project: memory_sizer

-Overview | -People | -Documentation | -Download | -OpenCores Mail list | -Contact me
-

-The People

-John E. Clayton from Scottsdale, Arizona, USA

Index: trunk/download.shtml =================================================================== --- trunk/download.shtml (revision 6) +++ trunk/download.shtml (nonexistent) @@ -1,24 +0,0 @@ -Project: risc16f84

-Overview | -People | -Documentation | -Download | -OpenCores Mail list | -Contact me
-

Download

-

Allright, here are "the goods!"

- -

Downloads:

-

-

risc16f84_clk2x.v. This file contains the stripped down 16f84 microcontroller: 1 interrupt input, no watch dog timer, no port A and B, plus the Auxiliary bus (which handles much more than Ports A and B), plus it runs at 2 clock cycles per instruction. -

risc16f84_small.v. This file contains the 16f84 Verilog code without EEPROM interface, with only a single interrupt input. -

risc16f84_lite.v. This file contains the 16f84 Verilog code without EEPROM interface. -

risc16f84.v. This file contains the full-blown 16f84 Verilog code. -

-

-b11_risc16f84_05_07_02.zip. -This file contains an example of the risc16f84_clk2x module in use. The top level module is "top.v" It uses tri-state buffers for data buses, except for the Xilinx DPRAM used to implement the 512 byte register file, which has separate data in and data out buses. There is support for hardware breakpoints, single stepping and resetting the processor through "rs232_syscon" commands given through a serial port (see opencores project at rs232_syscon).

-

This entire project fits into a Xilinx XC2S200 chip, taking up only about 950 slices or so, and all 14 of the DPRAM blocks (9 of the DPRAMS for a "pixel" memory for a 128 by 96 pixel display that I implemented with this project. You can remove these from the project, add new registers, create new peripherals -- whatever you like.) -

NOTE: In order to get these examples to work on your own board, you will need to generate a correct BAUD clock on your board -- see the file "serial.v" for details. Also, you will need some "level translating" circuit to change the LVTTL level signals coming out of the Xilinx chip into RS232 levels for connection to your computer's serial port. Be sure to re-assign the IO constraints to match the desired pinouts on your board, and add debug outputs if you like, so that you can view what is happening on a logic analyzer... Or, you could also simulate these modules! -

- Index: trunk/b13c_environment.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: trunk/b13c_environment.zip =================================================================== --- trunk/b13c_environment.zip (revision 6) +++ trunk/b13c_environment.zip (nonexistent)
trunk/b13c_environment.zip Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: trunk/index.shtml =================================================================== --- trunk/index.shtml (revision 6) +++ trunk/index.shtml (nonexistent) @@ -1,7 +0,0 @@ -Project: risc16f84

-People | -Documentation | -Download | -OpenCores Mail list | -Contact me

Description

The risc16f84 project is intended to provide a small, easy to use microcontroller in Verilog. The original code was VHDL, but I have done a wonderful translation of it into good clean Verilog code. (Well, I think it is wonderful, anyway.) The VHDL code was called "CQPIC" and it was published in 1999 by Sumio Morioka of Japan, in the December 1999 issue of "Transistor Gijutsu Magazine." I did the translation by hand, and then tested the design in actual hardware by running C code on it, and looking for correct behavior. I realize that this is not 100% test coverage, but I have found and fixed several bugs by this method -- including an error in the carry bit logic of the original code! There are four separate versions of the microcontroller presented here. The "original" one is called "risc16f84.v" and it includes all the logic needed to implement the entire 16f84 chip functionality as published in the original article.

However, I have realized over time, that a person using a microcontroller inside of an FPGA does not have the same constraints (i.e. on port sizes, number of pins, multiple functions needed on each pin, etc.) as the original chip designers, and so I have taken liberty in the other three versions, to simplify the logic by removing items that may not be wanted inside of an FPGA or ASIC implementation. For example, there is a version called "risc16f84_lite.v" which has no interface for the EEPROM...

Another version, called "risc16f84_small.v" further eliminates the multiple interrupt sources present on the original chip (since in a PIC there is only one interrupt vector defined, so interrupt service routines must do some "checking" anyway to determine the source of an interrupt - why bother having separate inputs defined? Just make up your own interrupt structure and use it the way you like inside of your chip!)

Finally, the fourth version, called "risc16f84_clk2x.v" further removes the port A and port B interfaces, since you can create as many ports as you like inside of your own chip. Toward this end, "risc16f84_clk2x.v" also includes an "auxiliary" bus interface, allowing the microcontroller to access 64k bytes of registers, ports and hardware peripherals, all defined within their own address space -- not within the limited register space of the PIC microcontrollers. I have used it to address a screen with 12288 pixels, and each pixel has its own address. It is easy to define addresses for the auxiliary bus components in most PIC code generation tools, so this works out nicely.

The code is written in Verilog, and was sythesized into a Xilinx SpartanII XC2S200 chip. Debugging was done in actual hardware, with an HP16500 series logic analyzer, and there are no simulation testbenches for these modules.

-

The design team welcomes any kind of help and feedback on these cores. If you are interested in further development of this project, please contact us.


Current Status:

  • The "risc16f84_clk2x.v" core has been coded completely, synthesized and tested for correct operation (and debugged!) inside a Xilinx XC2S200 chip. The tools used for development were the Xilinx Foundation 3.1i (non-ISE) tools.
  • The original "risc16f84.v" supports execution with 4 clocks per instruction, as in PIC microcontrollers.
  • The "risc16f84_clk2x" version uses only 2 clocks per instruction.
  • The "risc16f84_clk2x.v" core was tested at 49.125 MHz (approx. 25 MIPS), and uses 321 Virtex slices.
  • Xilinx DPRAM blocks were used to implement the processor register space and program ROM. These RAMs are dual-ported, so I have mapped the other port into the "auxiliary bus" space.
  • Debugging is aided by the use of "rs232_syscon.v" which is a hardware "monitor" that allows read/write of addresses on the auxiliary bus.
  • Since the registers and all useful peripherals are present on the auxiliary bus, single stepping and hardware breakpoints are implemented through the rs232_syscon interface (a serial port connects to a terminal window.)
  • I have been downloading C code through the serial port, in the form of rs232_syscon write commands.
  • A PERL script transforms s-record files into rs232_syscon write commands.
  • The cores are parameterized.
  • The code has good comments.

Maintainer(s):

Mailing-list:

\ No newline at end of file Index: trunk/documentation.shtml =================================================================== --- trunk/documentation.shtml (revision 6) +++ trunk/documentation.shtml (nonexistent) @@ -1,17 +0,0 @@ -Project: risc16f84

-Overview | -People | -Documentation | -Download | -Opencores Mail list | -Contact me
-

Documentation

-The data sheet for a 16F84A microcontroller from Microchip contains a superset of all of the instruction formats supported in "risc16f84_clk2x.v" For example, the "CLRWDT" instruction is not supported in "risc16f84_clk2x.v" because there is no watch dog timer. Also, ports A and B do not exist in "risc16f84_clk2x.v" so the user should be aware that this is NOT a fully compatible PIC type microcontroller. Much of the existing PIC code WILL NOT RUN on this microcontroller design because of these incompatibilities, and many libraries of code provided with PIC compilers will depend upon features that are not supported in this module. -However, new code which is written specifically for the "risc16f84_clk2x.v" design will run just fine. -

-

Interrupts have not been tested at this time.

-

In order to get up and running with this module, please examine the example code which shows how the module was used during testing. Also, the code is full of good comments, and there is a fairly detailed explanation of the working of the module in the file header.

-

- - - Index: trunk/risc16f84_clk2x.v =================================================================== --- trunk/risc16f84_clk2x.v (revision 6) +++ trunk/risc16f84_clk2x.v (nonexistent) @@ -1,963 +0,0 @@ -//--------------------------------------------------------------------------- -// RISC 16F84 "clk2x" core -// -// This file is part of the "risc_16F84" project. -// http://www.opencores.org/cores/risc_16F84 -// -// -// Description: See description below (which suffices for IP core -// specification document.) -// -// Copyright (C) 1999 Sumio Morioka (original VHDL design version) -// Copyright (C) 2001 John Clayton and OPENCORES.ORG (this Verilog version) -// -// NOTE: This source code is free for educational/hobby use only. It cannot -// be used for commercial purposes without the consent of Microchip -// Technology incorporated. -// -// This source file may be used and distributed without restriction provided -// that this copyright statement is not removed from the file and that any -// derivative work contains the original copyright notice and the associated -// disclaimer. -// -// This source file is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This source is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -// License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this source. -// If not, download it from http://www.opencores.org/lgpl.shtml -// -//--------------------------------------------------------------------------- -// -// Author: John Clayton -// Date : January 29, 2002 -// -// (NOTE: Date formatted as day/month/year.) -// Update: 29/01/02 copied this file from memory_sizer.v (pared down). -// Translated the module and signal declarations. -// Transformed the instruction wires to lowercase. -// Transformed the addressing wires to lowercase. -// Update: 31/01/02 Translated the instruction decoder. -// Update: 5/02/02 Determined that stack is simply a circular buffer of -// 8 locations, 13 bits per location. Started translating -// "main_efsm" process. Added all code from piccore.vhd -// into this file for eventual translation. Concluded that -// "stack_full_node" is not needed. -// Update: 6/02/02 Translated the "ram_i_node" if/else precedural assignment. -// Update: 7/02/02 Changed all := to <=, changed all '0' to 0 and '1' to 1. -// Replaced all " downto " with ":". -// Finished translating QRESET state. -// Update: 20/02/02 Replaced all instances of Qreset with QRESET_PP. Also -// replaced other state designations with their new names. -// Finished translating Q1, Q2 states. -// Update: 22/02/02 Translated section 2-4-1-1 (aluout register) -// Update: 27/02/02 Replaced all "or" with "||" in if statements -// Replaced all "and" with "&&" in if statements. -// Replaced all "not" with "~" in if statements. -// Finished translating Q3,Q4 states. -// Translated output signal assignments at end of code. -// Translated interrupt trigger processes. -// Update: 28/02/02 Finished translation of WDT and TMR0 prescaler. -// Trimmed line length to 80 characters throughout. -// Prepared to attempt initial syntax checking. -// Cleaned up some naming conventions, and verified that -// all I/O pins have _i or _o appended in the body of the -// code. -// Update: 03/04/02 Changed "progdata_i" to "prog_dat_i" Also changed -// "progadr_o" to "prog_adr_o" -// Update: 04/04/02 Created new file "risc16f84_lite.v" This file is reduced -// and simplified from the original "risc16f84.v" file. -// Specifically, I am removing EEPROM support, and -// consolidating porta and portb I/O pins so that they -// are bidirectional. -// Update: 04/04/02 Created a new file "risc16f84_small.v" This file is -// further reduced and simplified from "risc16f84_lite.v" -// Specifically, I am removing the prescaler, TMR0 and WDT. -// Also, I am removing support for portb interrupts, leaving -// only rb0/int as an interrupt source. This pin will be -// the only way to wake up from the SLEEP instruction... -// Obviously, the CLEARWDT instruction will no longer do -// anything. -// Update: 05/04/02 Removed the "powerdown_o", "startclk_o" and "clk_o" pins -// from the small design. Also removed "rbpu_o", so if you -// want pullups, you have to add them explicitly in the -// constraints file, and option_reg[7] doesn't control them. -// Update: 08/04/02 Decided to modify "risc16f84_small.v" in order to try for -// more performance (only 2 states per instruction!) -// The new file is called "risc16f84_clk2x.v" The resulting -// code was synthesized, but not tested yet. -// Update: 11/04/02 Decided to remove porta and portb from this unit, and add -// instead an auxiliary bus, which is intended to allow I/O -// using an indirect approach, similar to using the FSR. -// However, the aux_adr_o is 16 bits wide, so that larger -// RAM may be accessed indirectly by the processor... The use -// of FSR for this purpose proved undesirable, since any new -// page of RAM contains "holes" to accomodate the registers -// in the first 12 locations (including FSR!) so that large -// contiguous blocks of memory could not be accessed in an -// effective way. This auxiliary bus solves that problem. -// Since this processor is implemented inside of an FPGA, -// and it is not a goal to maintain compatibility with -// existing libraries of code, there is no need to maintain -// porta and portb in the hardware. -// The aux_adr_lo and aux_adr_hi registers are located at -// 88h and 89h, and the aux_dat_io location is decoded at -// 08h. -// Also, changed to using "ram_we_o" instead of "readram_o" -// and "writeram_o" -// Update: 16/04/02 Added clock enable signal, for processor single stepping. -// "aux_dat_io" is only driven when "clk_en_i" is high... -// Update: 17/04/02 Removed "reset_condition" and moved "inc_pc_node" out of -// the clocking area, making it non-registered. In fact, I -// moved everything other than the state machine out of the -// clocked logic section. Changed "aluout_reg" to "aluout" -// since it is no longer registered. -// Update: 26/04/02 Fixed bug in aluout logic. The AND and OR functions were -// coded with logical AND/OR instead of bitwise AND/OR! -// Update: 26/04/02 Changed location of aux_adr_lo and aux_adr_hi registers -// to 05h and 06h, respectively. This was done to save -// code space because when using the aux data bus, no bank -// switching is necessary since they will now reside in the -// same bank. -// Update: 01/05/02 Fixed another bug -- the rrf and rlf instructions were -// coded incorrectly. -// Update: 03/05/02 Fixed another bug -- the carry bit was incorrect (the -// problem was discovered while performing SUBWF X,W where -// W contained 0 and X contained 1. (1-0). The logic for -// the carry bit appears to have been incorrect even in -// the original VHDL code by Sumio Morioka. -// Update: 11/18/02 Fixed bug in PCL addressing mode (near line 791) -// Removed parameters associated with WDT. -// Update: 11/25/02 Re-wrote much of the main FSM. Attempted to generate logic -// to recognize the falling edge of an interrupt, and was -// unsuccessful (not simulation, actual hardware tests.) -// Realized that falling edge interrupt can be equivalent to -// rising edge interrupt with a NOT gate on the signal. Since -// NOTs are practically free inside of an FPGA, decided to -// abandon the negative edge aspect of recognizing interrupts. -// Therefore, removed the "option_reg" since it is no longer -// needed in this design. -// Update: 08/08/03 Fixed a mathematical error, which was introduced by the bug -// fix of 03/05/02. The fix of 03/05/02 correctly generated the -// C bit for subtraction of zero, but unfortunately it introduced -// an error such that all subtraction results were off by 1. -// Obviously, this was unacceptable, and I think it has been fixed -// by the new signals "c_subtract_zero" and "c_dig_subtract_zero" -// Update: 10/24/05 Added code patches to fix interrupt bug and status flag updates -// when using literal value of 0x03. These bugs were reported by -// an opencores.org user. Added three "disable_status_x" signals. -// Modified file still needs to be tested. -// -// Description -//--------------------------------------------------------------------------- -// This logic module implements a small RISC microcontroller, with functions -// and instruction set very similar to those of the Microchip 16F84 chip. -// This work is a translation (from VHDL to Verilog) of the "CQPIC" design -// published in 1999 by Sumio Morioka of Japan, and published in the December -// 1999 issue of "Transistor Gijutsu Magazine." The translation was performed -// by John Clayton, without the use of any translation tools. -// -// Original version used as basis for translation: CQPIC version 1.00b -// (December 10, 2000) -// -// Further revisions and re-writing have been completed on this code by John -// Clayton. The interrupt mechanism has been completely re-done, and the -// way in which the program counter is generated is expressed in a new way. -// -// In the comments, a "cycle" is defined as a processor cycle of 2 states. -// Thus, passing through states Q2_PP and Q4_PP completes one cycle. -// The numbers "1-3" and so forth are left from the comments in the original -// source code used as the basis of the translation. -//--------------------------------------------------------------------------- - -`define STATEBIT_SIZE 2 // Size of state machine register (bits) - - -module risc16f84_clk2x ( - prog_dat_i, // [13:0] ROM read data - prog_adr_o, // [12:0] ROM address - ram_dat_i, // [7:0] RAM read data - ram_dat_o, // [7:0] RAM write data - ram_adr_o, // [8:0] RAM address; ram_adr[8:7] indicates RAM-BANK - ram_we_o, // RAM write strobe (H active) - aux_adr_o, // [15:0] Auxiliary address bus - aux_dat_io, // [7:0] Auxiliary data bus (tri-state bidirectional) - aux_we_o, // Auxiliary write strobe (H active) - int0_i, // PORT-B(0) INT - reset_i, // Power-on reset (H active) - clk_en_i, // Clock enable for all clocked logic - clk_i // Clock input -); - - -// You can change the following parameters as you would like -parameter STACK_SIZE_PP = 8; // Size of PC stack -parameter LOG2_STACK_SIZE_PP = 3; // Log_2(stack_size) - -// State definitions for state machine, provided as parameters to allow -// for redefinition of state values by the instantiator if desired. -parameter Q2_PP = 2'b00; // state Q2 -parameter Q4_PP = 2'b01; // state Q4 -parameter QINT_PP = 2'b10; // interrupt state (substitute for Q4) -parameter QSLEEP_PP = 2'b11; // sleep state - - -// I/O declarations - - // program ROM data bus/address bus -input [13:0] prog_dat_i; // ROM read data -output [12:0] prog_adr_o; // ROM address - - // data RAM data bus/address bus/control signals -input [7:0] ram_dat_i; // RAM read data -output [7:0] ram_dat_o; // RAM write data -output [8:0] ram_adr_o; // RAM address; ram_adr[8:7] indicates RAM-BANK -output ram_we_o; // RAM write strobe (H active) - - // auxiliary data bus/address bus/control signals -output [15:0] aux_adr_o; // AUX address bus -inout [7:0] aux_dat_io; // AUX data bus -output aux_we_o; // AUX write strobe (H active) - - // interrupt input -input int0_i; // INT - - // CPU reset -input reset_i; // Power-on reset (H active) - - // CPU clock -input clk_en_i; // Clock enable input -input clk_i; // Clock input - - -// Internal signal declarations - - // User registers -reg [7:0] w_reg; // W -reg [12:0] pc_reg; // PCH/PCL -- Address currently being fetched -reg [12:0] old_pc_reg; // Address fetched previous to this one. -reg [7:0] status_reg; // STATUS -reg [7:0] fsr_reg; // FSR -reg [4:0] pclath_reg; // PCLATH -reg [7:0] intcon_reg; // INTCON -reg [7:0] aux_adr_hi_reg; // AUX address high byte -reg [7:0] aux_adr_lo_reg; // AUX address low byte - - // Internal registers for controlling instruction execution -reg [13:0] inst_reg; // Holds fetched op-code/operand -reg [7:0] aluinp1_reg; // data source (1 of 2) -reg [7:0] aluinp2_reg; // data source (2 of 2) -reg exec_stall_reg; // if H (i.e. after GOTO etc), stall execution. - - // Stack - // stack (array of data-registers) -reg [12:0] stack_reg [STACK_SIZE_PP-1:0]; - // stack pointer -reg [LOG2_STACK_SIZE_PP-1:0] stack_pnt_reg; -wire [12:0] stack_top; // More compatible with sensitivity list than - // "stack_reg[stack_pnt_reg]" - - // Interrupt registers/nodes -wire int_condition; // Indicates that an interrupt should be recognized -wire intrise; // High indicates edge was detected -reg intrise_reg; // detect positive edge of PORT-B inputs - // Synchronizer for interrupt -reg inte_sync_reg; - - // State register -reg [`STATEBIT_SIZE-1:0] state_reg; -reg [`STATEBIT_SIZE-1:0] next_state_node; - - // Result of decoding instruction -- only 1 is active at a time -wire inst_addlw; -wire inst_addwf; -wire inst_andlw; -wire inst_andwf; -wire inst_bcf; -wire inst_bsf; -wire inst_btfsc; -wire inst_btfss; -wire inst_call; -wire inst_clrf; -wire inst_clrw; -wire inst_comf; -wire inst_decf; -wire inst_decfsz; -wire inst_goto; -wire inst_incf; -wire inst_incfsz; -wire inst_iorlw; -wire inst_iorwf; -wire inst_movlw; -wire inst_movf; -wire inst_movwf; -wire inst_retfie; -wire inst_retlw; -wire inst_ret; -wire inst_rlf; -wire inst_rrf; -wire inst_sleep; -wire inst_sublw; -wire inst_subwf; -wire inst_swapf; -wire inst_xorlw; -wire inst_xorwf; - - // Result of calculating RAM access address -wire [8:0] ram_adr_node; // RAM access address - - // These wires indicate accesses to special registers... - // Only 1 is active at a time. -wire addr_pcl; -wire addr_stat; -wire addr_fsr; -wire addr_pclath; -wire addr_intcon; -wire addr_aux_adr_lo; -wire addr_aux_adr_hi; -wire addr_aux_dat; -wire addr_sram; - - // Other output registers (for removing hazards) -reg ram_we_reg; // data-sram write strobe -reg aux_we_reg; // AUX write strobe - - - // Signals used in "main_efsm" procedure - // (Intermediate nodes used for resource sharing.) -wire [7:0] ram_i_node; // result of reading RAM/Special registers -wire [7:0] mask_node; // bit mask for logical operations -wire [8:0] add_node; // result of 8bit addition -wire [4:0] addlow_node; // result of low-4bit addition -wire aluout_zero_node; // H if ALUOUT = 0 - -reg [12:0] next_pc_node; // value of next PC -reg [7:0] aluout; // result of calculation -reg writew_node; // H if destination is W register -reg writeram_node; // H if destination is RAM/Special registers -reg c_subtract_zero; // High for special case of C bit, when subtracting zero -reg c_dig_subtract_zero; // High for special case of C bit, when subtracting zero - -wire next_exec_stall; - // Three signals used to disable status flag updates. Fixes bug when literal 0x03 is used. -wire disable_status_z; -wire disable_status_c; -wire disable_status_dc; - -//-------------------------------------------------------------------------- -// Instantiations -//-------------------------------------------------------------------------- - - -//-------------------------------------------------------------------------- -// Functions & Tasks -//-------------------------------------------------------------------------- - -//-------------------------------------------------------------------------- -// Module code -//-------------------------------------------------------------------------- - -// This represents the instruction fetch from program memory. -// inst_reg[13:0] stores the instruction. This happens at the end of Q4. -// So the memory access time is one processor cycle (2 clocks!) minus -// the setup-time of this register, and minus the delay to drive the -// address out onto the prog_adr_o bus. -always @(posedge clk_i) -begin - if (reset_i) inst_reg <= 0; - else if (clk_en_i && (state_reg == Q4_PP)) inst_reg <= prog_dat_i; -end - -// NOTE: There is an extra "15th" bit of inst_reg, which represents an -// interrupt execution cycle. This is included in inst_reg so that when -// an interrupt instruction is executing, it effectively "pre-empts" the -// other instructions. -// The fifteenth bit, inst_reg[14], is set by the interrupt logic. - -// Decode OPcode (see pp.54 of PIC16F84 data sheet) -// only 1 signal of the following signals will be '1' -assign inst_call = (inst_reg[13:11] == 3'b100 ); -assign inst_goto = (inst_reg[13:11] == 3'b101 ); -assign inst_bcf = (inst_reg[13:10] == 4'b0100 ); -assign inst_bsf = (inst_reg[13:10] == 4'b0101 ); -assign inst_btfsc = (inst_reg[13:10] == 4'b0110 ); -assign inst_btfss = (inst_reg[13:10] == 4'b0111 ); -assign inst_movlw = (inst_reg[13:10] == 4'b1100 ); -assign inst_retlw = (inst_reg[13:10] == 4'b1101 ); -assign inst_sublw = (inst_reg[13:9] == 5'b11110 ); -assign inst_addlw = (inst_reg[13:9] == 5'b11111 ); -assign inst_iorlw = (inst_reg[13:8] == 6'b111000 ); -assign inst_andlw = (inst_reg[13:8] == 6'b111001 ); -assign inst_xorlw = (inst_reg[13:8] == 6'b111010 ); -assign inst_subwf = (inst_reg[13:8] == 6'b000010 ); -assign inst_decf = (inst_reg[13:8] == 6'b000011 ); -assign inst_iorwf = (inst_reg[13:8] == 6'b000100 ); -assign inst_andwf = (inst_reg[13:8] == 6'b000101 ); -assign inst_xorwf = (inst_reg[13:8] == 6'b000110 ); -assign inst_addwf = (inst_reg[13:8] == 6'b000111 ); -assign inst_movf = (inst_reg[13:8] == 6'b001000 ); -assign inst_comf = (inst_reg[13:8] == 6'b001001 ); -assign inst_incf = (inst_reg[13:8] == 6'b001010 ); -assign inst_decfsz = (inst_reg[13:8] == 6'b001011 ); -assign inst_rrf = (inst_reg[13:8] == 6'b001100 ); -assign inst_rlf = (inst_reg[13:8] == 6'b001101 ); -assign inst_swapf = (inst_reg[13:8] == 6'b001110 ); -assign inst_incfsz = (inst_reg[13:8] == 6'b001111 ); -assign inst_movwf = (inst_reg[13:7] == 7'b0000001 ); -assign inst_clrw = (inst_reg[13:7] == 7'b0000010 ); -assign inst_clrf = (inst_reg[13:7] == 7'b0000011 ); -assign inst_ret = (inst_reg[13:0] == 14'b00000000001000); -assign inst_retfie = (inst_reg[13:0] == 14'b00000000001001); -assign inst_sleep = (inst_reg[13:0] == 14'b00000001100011); - - -// Calculate RAM access address (see pp.19 of PIC16F84 data sheet) - - // if "d"=0, indirect addressing is used, so RAM address is BANK+FSR - // otherwise, RAM address is BANK+"d" - // (see pp.19 of PIC16F84 data sheet) -assign ram_adr_node = (inst_reg[6:0]==0)?{status_reg[7],fsr_reg[7:0]}: - {status_reg[6:5],inst_reg[6:0]}; - - // check if this is an access to external RAM or not -assign addr_sram = (ram_adr_node[6:0] > 7'b0001011); //0CH-7FH,8CH-FFH - - // check if this is an access to special register or not - // only 1 signal of the following signals will be '1' -assign addr_pcl = (ram_adr_node[6:0] == 7'b0000010); // 02H, 82H -assign addr_stat = (ram_adr_node[6:0] == 7'b0000011); // 03H, 83H -assign addr_fsr = (ram_adr_node[6:0] == 7'b0000100); // 04H, 84H -assign addr_aux_dat = (ram_adr_node[7:0] == 8'b00001000); // 08H -assign addr_pclath = (ram_adr_node[6:0] == 7'b0001010); // 0AH, 8AH -assign addr_intcon = (ram_adr_node[6:0] == 7'b0001011); // 0BH, 8BH -assign addr_aux_adr_lo = (ram_adr_node[7:0] == 8'b00000101); // 05H -assign addr_aux_adr_hi = (ram_adr_node[7:0] == 8'b00000110); // 06H - -// construct bit-mask for logical operations and bit tests -assign mask_node = 1 << inst_reg[9:7]; - -// disable write access for status flags -assign disable_status_z = (inst_addwf || inst_andwf || inst_clrf || - inst_clrw || inst_comf || inst_decf || - inst_incf || inst_iorwf || inst_movf || - inst_subwf || inst_xorwf || inst_addlw || - inst_andlw || inst_iorlw || inst_iorlw || - inst_sublw || inst_xorlw) ? 1:0; -assign disable_status_c = (inst_addwf || inst_subwf || inst_rlf || - inst_rrf || inst_addlw || inst_sublw ) ? 1:0; -assign disable_status_dc = (inst_addwf || inst_subwf || inst_addlw || - inst_sublw ) ? 1:0; - - -// Create the exec_stall signal, based on the contents of the currently -// executing instruction (inst_reg). next_exec_stall reflects the state -// to assign to exec_stall following the conclusion of the next Q4 state. -// All of these instructions cause an execution stall in the next cycle -// because they modify the program counter, and a new value is presented -// for fetching during the stall cycle, during which time no instruction -// should be executed. -// -// The conditional instructions are given along with their conditions for -// execution. If the conditions are not met, there is no stall and nothing -// to execute. -assign next_exec_stall = ( - inst_goto - || inst_call - || inst_ret - || inst_retlw - || inst_retfie - || ( - (inst_btfsc || inst_decfsz || inst_incfsz) - && aluout_zero_node - ) - || (inst_btfss && ~aluout_zero_node) - || (addr_pcl && writeram_node) - ); -always @(posedge clk_i) -begin - if (reset_i) exec_stall_reg <= 0; - else if (clk_en_i && (state_reg == QINT_PP)) exec_stall_reg <= 1; - else if (clk_en_i && (state_reg == Q4_PP)) - exec_stall_reg <= (next_exec_stall && ~exec_stall_reg); - // exec stall should never be generated during a stall cycle, because - // a stall cycle doesn't execute anything... -end - -assign stack_top = stack_reg[stack_pnt_reg]; -// Formulate the next pc_reg value (the program counter.) -// During stall cycles, the pc is simply incremented... -always @( - pc_reg - or pclath_reg - or aluout - or stack_pnt_reg - or stack_top - or inst_ret - or inst_retlw - or inst_retfie - or inst_goto - or inst_call - or inst_reg - or writeram_node - or addr_pcl - or exec_stall_reg - ) -begin - if (~exec_stall_reg &&(inst_ret || inst_retlw || inst_retfie)) - next_pc_node <= stack_top; - else if (~exec_stall_reg &&(inst_goto || inst_call)) - next_pc_node <= {pclath_reg[4:3],inst_reg[10:0]}; - else if (~exec_stall_reg && (writeram_node && addr_pcl)) - // PCL is data-destination, but update the entire PC. - next_pc_node <= {pclath_reg[4:0],aluout}; - else - next_pc_node <= pc_reg + 1; -end - -// Set the program counter -// If the sleep instruction is executing, then the PC is not allowed to be -// updated, since the processor will "freeze" and the instruction being fetched -// during the sleep instruction must be executed upon wakeup interrupt. -// Obviously, if the PC were to change at the end of the sleep instruction, then -// a different (incorrect) address would be fetched during the sleep time. -always @(posedge clk_i) -begin - if (reset_i) begin - pc_reg <= 0; - old_pc_reg <= 0; - end - else if (clk_en_i && (state_reg == QINT_PP)) - begin - old_pc_reg <= pc_reg; - pc_reg <= 4; - end - else if (clk_en_i && ~inst_sleep && (state_reg == Q4_PP)) - begin - old_pc_reg <= pc_reg; - pc_reg <= next_pc_node; - end -end - -// 1. Intermediate nodes for resource sharing - -// Tri-state drivers instead of a huge selector... It produces smaller -// results, and runs faster. -assign ram_i_node = (addr_sram) ?ram_dat_i:8'bZ; -assign ram_i_node = (addr_pcl) ?pc_reg[7:0]:8'bZ; -assign ram_i_node = (addr_stat) ?status_reg:8'bZ; -assign ram_i_node = (addr_fsr) ?fsr_reg:8'bZ; -assign ram_i_node = (addr_aux_dat) ?aux_dat_io:8'bZ; -assign ram_i_node = (addr_pclath) ?{3'b0,pclath_reg}:8'bZ; -assign ram_i_node = (addr_intcon) ?intcon_reg:8'bZ; -assign ram_i_node = (addr_aux_adr_lo) ?aux_adr_lo_reg:8'bZ; -assign ram_i_node = (addr_aux_adr_hi) ?aux_adr_hi_reg:8'bZ; - -// 1-3. Adder (ALU) -// full 8bit-addition, with carry in/out. -// Note that "temp" and "dtemp" are intended to be thrown away. -// Also, addlow_node[3:0] are thrown away. -// Even though they are assigned, they should never be used. -assign add_node = {1'b0,aluinp1_reg} - + {1'b0,aluinp2_reg}; -// lower 4bit-addition -assign addlow_node = {1'b0,aluinp1_reg[3:0]} - + {1'b0,aluinp2_reg[3:0]}; - -// 1-4. Test if aluout = 0 -assign aluout_zero_node = (aluout == 0)?1:0; - -// 1-5. Determine destination -always @( - inst_reg - or inst_movwf - or inst_bcf - or inst_bsf - or inst_clrf - or inst_movlw - or inst_addlw - or inst_sublw - or inst_andlw - or inst_iorlw - or inst_xorlw - or inst_retlw - or inst_clrw - or inst_movf - or inst_swapf - or inst_addwf - or inst_subwf - or inst_andwf - or inst_iorwf - or inst_xorwf - or inst_decf - or inst_incf - or inst_rlf - or inst_rrf - or inst_decfsz - or inst_incfsz - or inst_comf - ) -begin - if (inst_movwf || inst_bcf || inst_bsf || inst_clrf) - begin - writew_node <= 0; - writeram_node <= 1; - end - else if ( inst_movlw || inst_addlw || inst_sublw || inst_andlw - || inst_iorlw || inst_xorlw || inst_retlw || inst_clrw) - begin - writew_node <= 1; - writeram_node <= 0; - end - else if ( inst_movf || inst_swapf || inst_addwf || inst_subwf - || inst_andwf || inst_iorwf || inst_xorwf || inst_decf - || inst_incf || inst_rlf || inst_rrf || inst_decfsz - || inst_incfsz || inst_comf) - begin - writew_node <= ~inst_reg[7]; // ("d" field of fetched instruction) - writeram_node <= inst_reg[7]; // ("d" field of fetched instruction) - end - else - begin - writew_node <= 0; - writeram_node <= 0; - end -end // End of determine destination logic - - - - -// 2-4-1. Calculation and store result into alu-output register - -always @( - add_node - or aluinp1_reg - or aluinp2_reg - or status_reg - or inst_reg - or inst_movwf - or inst_bcf - or inst_bsf - or inst_btfsc - or inst_btfss - or inst_clrf - or inst_addlw - or inst_sublw - or inst_andlw - or inst_iorlw - or inst_xorlw - or inst_retlw - or inst_clrw - or inst_swapf - or inst_addwf - or inst_subwf - or inst_andwf - or inst_iorwf - or inst_xorwf - or inst_decf - or inst_incf - or inst_rlf - or inst_rrf - or inst_decfsz - or inst_incfsz - or inst_comf - ) -begin - // 2-4-1-1. Set aluout register - // Rotate left - if (inst_rlf) - aluout <= {aluinp1_reg[6:0],status_reg[0]}; - // Rotate right - else if (inst_rrf) - aluout <= {status_reg[0],aluinp1_reg[7:1]}; - // Swap nibbles - else if (inst_swapf) - aluout <= {aluinp1_reg[3:0],aluinp1_reg[7:4]}; - // Logical inversion - else if (inst_comf) - aluout <= ~aluinp1_reg; - // Logical AND, bit clear/bit test - else if ( inst_andlw || inst_andwf || inst_bcf || inst_btfsc - || inst_btfss) - aluout <= (aluinp1_reg & aluinp2_reg); - // Logical OR, bit set - else if (inst_bsf || inst_iorlw || inst_iorwf) - aluout <= (aluinp1_reg | aluinp2_reg); - // Logical XOR - else if (inst_xorlw || inst_xorwf) - aluout <= (aluinp1_reg ^ aluinp2_reg); - // Addition, Subtraction, Increment, Decrement - else if ( inst_addlw || inst_addwf || inst_sublw || inst_subwf - || inst_decf || inst_decfsz || inst_incf || inst_incfsz) - aluout <= add_node[7:0]; - // Pass through - else aluout <= aluinp1_reg; -end - - -// MAIN EFSM: description of register value changes in each clock cycle -always @(posedge clk_i) -begin - // Assign reset (default) values of registers - if (reset_i) - begin - status_reg[7:5] <= 3'b0; - pclath_reg <= 0; // 0 - intcon_reg[7:1] <= 7'b0; - aux_adr_lo_reg <= 0; - aux_adr_hi_reg <= 0; - ram_we_reg <= 0; - status_reg[4] <= 1; // /T0 = 1 - status_reg[3] <= 1; // /PD = 1 - stack_pnt_reg <= 0; // Reset stack pointer - end // End of reset assignments - else if (~exec_stall_reg && clk_en_i) - begin // Execution ceases during a stall cycle. - if (state_reg == Q2_PP) // 2-3. Q2 cycle - begin - // 2-3-1. Read data-RAM and store values to alu-input regs - // 2-3-1-1. Set aluinp1 register (source #1) - if ( inst_movf || inst_swapf || inst_addwf || inst_subwf - || inst_andwf || inst_iorwf || inst_xorwf || inst_decf - || inst_incf || inst_rlf || inst_rrf || inst_bcf - || inst_bsf || inst_btfsc || inst_btfss || inst_decfsz - || inst_incfsz || inst_comf) - - aluinp1_reg <= ram_i_node; // RAM/Special registers - else - if ( inst_movlw || inst_addlw || inst_sublw || inst_andlw - || inst_iorlw || inst_xorlw || inst_retlw) - aluinp1_reg <= inst_reg[7:0]; // Immediate value ("k") - else - if ( inst_clrf || inst_clrw) aluinp1_reg <= 0; // 0 - else aluinp1_reg <= w_reg; // W register - - // 2-3-1-2. Set aluinp2 register (source #2) - c_subtract_zero <= 0; // default to non-special case - c_dig_subtract_zero <= 0; // default to non-special case - if (inst_decf || inst_decfsz) aluinp2_reg <= -1; // for decr. - else if (inst_incf || inst_incfsz) aluinp2_reg <= 1; // for incr. - // -1 * W register (for subtract) - else if (inst_sublw || inst_subwf) - begin - aluinp2_reg <= ~w_reg + 1; - c_subtract_zero <= (w_reg == 0); // Indicate special case - c_dig_subtract_zero <= (w_reg[3:0] == 0); // Indicate special case - end - // operation of BCF: AND with inverted mask ("1..101..1") - // mask for BCF: value of only one position is 0 - else if (inst_bcf) aluinp2_reg <= ~mask_node; - // operation of BSF: OR with mask_node ("0..010..0") - // operation of FSC and FSS: AND with mask_node, compare to 0 - else if (inst_btfsc || inst_btfss || inst_bsf) - aluinp2_reg <= mask_node; - else aluinp2_reg <= w_reg; // W register - - // 2-3-1-3. Set stack pointer register (pop stack) - if (inst_ret || inst_retlw || inst_retfie) - stack_pnt_reg <= stack_pnt_reg - 1; // cycles 3,2,1,0,7,6... - - // 2-4-1-3. Set data-SRAM write enable (hazard-free) - // Set the write enables depending on the destination. - // (These have been implemented as registers to avoid glitches? - // It is not known to me (John Clayton) whether any glitches would - // really occur. It might be possible to generate these signals - // using combinational logic only, without using registers! - ram_we_reg <= (writeram_node && addr_sram); - aux_we_reg <= (writeram_node && addr_aux_dat); - end // End of Q2 state - - //--------------------------------------------------------------------- - - else if (state_reg == QINT_PP) // Interrupt execution (instead of Q4_PP) - begin - // PORT-B0 INT - intcon_reg[1] <= 1; // set INTF - intcon_reg[7] <= 0; // clear GIE - stack_reg[stack_pnt_reg] <= old_pc_reg; // Push old PC - stack_pnt_reg <= stack_pnt_reg + 1; // increment stack pointer - // The old PC is pushed, so that the pre-empted instruction can be - // restarted later, when the retfie is executed. - end - - //--------------------------------------------------------------------- - - else if (state_reg == Q4_PP) // Execution & writing of results. - begin - - if (inst_call) - begin - stack_reg[stack_pnt_reg] <= pc_reg; // Push current PC - stack_pnt_reg <= stack_pnt_reg + 1; // increment stack pointer - end - - if (inst_retfie) // "return from interrupt" instruction - begin - intcon_reg[7] <= 1; // Set GIE - end - - // 2-4-1-2. Set C flag and DC flag - if (inst_addlw || inst_addwf || inst_sublw || inst_subwf) - begin - // c_dig_subtract_zero and c_subtract_zero are used to take care of the - // special case when subtracting zero, where the carry bit should be 1 - // (meaning no borrow). It is explicitly set by these signals during - // that condition. See 16F84 datasheet, page 8 for further information - // about the C bit. - status_reg[1] <= addlow_node[4] || c_dig_subtract_zero; // DC flag - status_reg[0] <= add_node[8] || c_subtract_zero; // C flag - end - else if (inst_rlf) status_reg[0] <= aluinp1_reg[7]; // C flag - else if (inst_rrf) status_reg[0] <= aluinp1_reg[0]; // C flag - - // 2-5-2. Store calculation result into destination, - // 2-5-2-1. Set W register - - if (writew_node) w_reg <= aluout; // write W reg - - - // 2-5-2-2. Set data RAM/special registers, - if (writeram_node) - begin - if (addr_stat) - begin - status_reg[7:5] <= aluout[7:5]; // write IRP,RP1,RP0 - // status(4),status(3)...unwritable, see below (/PD,/T0 part) - if( ~disable_status_c ) status_reg[0] <= aluout[0]; // write C - if( ~disable_status_dc ) status_reg[1] <= aluout[1]; // write DC - end - if (addr_fsr) fsr_reg <= aluout; // write FSR - if (addr_pclath) pclath_reg <= aluout[4:0]; // write PCLATH - if (addr_intcon) intcon_reg <= aluout; // write INTCON - if (addr_aux_adr_lo) aux_adr_lo_reg <= aluout; // write AUX low - if (addr_aux_adr_hi) aux_adr_hi_reg <= aluout; // write AUX high - end - - // 2-5-2-3. Set/clear Z flag. - if (addr_stat && ~disable_status_z) status_reg[2] <= aluout[2]; - else if ( inst_addlw || inst_addwf || inst_andlw || inst_andwf - || inst_clrf || inst_clrw || inst_comf || inst_decf - || inst_incf || inst_movf || inst_sublw || inst_subwf - || inst_xorlw || inst_xorwf || inst_iorlw || inst_iorwf ) - status_reg[2] <= aluout_zero_node; // Z=1 if result == 0 - - // 2-5-3. Clear RAM write enables (hazard-free) - ram_we_reg <= 0; - aux_we_reg <= 0; - - end // End of Q4 state - end // End of "if (~exec_stall_reg)" -end // End of process - - -// Calculation of next processor state. -// (Not including reset conditions, which are covered by the clocked logic, -// which also includes a "global clock enable." -always @( - state_reg - or inst_sleep - or inte_sync_reg - or exec_stall_reg - or int_condition - ) -begin - case (state_reg) - Q2_PP : if (int_condition) next_state_node <= QINT_PP; - else next_state_node <= Q4_PP; - Q4_PP : if (~exec_stall_reg && inst_sleep) next_state_node <= QSLEEP_PP; - else next_state_node <= Q2_PP; - QINT_PP : next_state_node <= Q2_PP; - QSLEEP_PP : if (inte_sync_reg) next_state_node <= Q2_PP; - else next_state_node <= QSLEEP_PP; - // Default condition provided for convention and completeness - // only. Logically, all of the conditions are already covered. - default : next_state_node <= Q2_PP; - endcase -end - - -// Clocked state transitions, based upon dataflow (non-clocked logic) in -// the previous always block. -always @(posedge clk_i) -begin - if (reset_i) state_reg <= Q2_PP; - else if (clk_en_i) state_reg <= next_state_node; -end // End of process - - -// Detect external interrupt requests -// You can code multiple interrupts if you wish, or use the single interrupt -// provided and simply have the interrupt service routine (ISR) check to find -// out the source of the interrupt, by or-ing together all of the interrupt -// sources and providing a readable register of their values at the time -// the interrupt occurred. -// -// When an interrupt is recognized by the processor, this is signified by -// entering "QINT_PP," which is treated like an executable instruction. -// The interrupt instruction can only be executed when not in a stall condition. -// It simply "pre-empts" the instruction that would have been executed during -// that cycle. Then, when retfie is executed, the pre-empted instruction is -// re-started (the stall cycle of the retfie is when the address of the -// instruction being re-started is fetched.) -// -// I was unable to obtain correct operation for capturing the negative edge, -// so I am discarding it. If one really needs to generate an interrupt on the -// falling edge, just use an inverted version of the signal (the inversion is -// often "free" inside of an FPGA anyhow.) -// -// Upon further testing, I discovered that even the rising edge "trigger" was not -// really truly an edge detection, it was more like a "set-reset" flip flop -// type of behavior. Rather than mess around with it any more, I am implementing -// a clocked "poor man's rising edge detector." -// Capture the rising edge of the interrupt input... This part is self clearing. -// It also means that the interrupt must last longer than one clock cycle in -// order to be properly recognized. (It is "pseudo edge triggered", not a true -// rising edge trigger.) -// When the interrupt is recognized, inte_sync_reg is cleared. - - -always @(posedge clk_i) -begin - if (clk_en_i) intrise_reg <= int0_i; -end // process -assign intrise = (int0_i && ~intrise_reg); - -// The inte_sync_reg signal is used for waking up from SLEEP. -// (this flip flop is also a synchronizer to minimize the -// possibility of metastability due to changes at the input -// occurring at the same time as the processor clock edge...) -// It might be possible to eliminate this step, and issue the interrupt -// directly without this intermediate synchronizer flip-flop. -always @(posedge clk_i) -begin - if (reset_i || (state_reg == QINT_PP)) inte_sync_reg <= 0; - else if (clk_en_i && intrise && intcon_reg[4]) inte_sync_reg <= 1; -end - -// Issue an interrupt when the interrupt is present. -// Also, do not issue an interrupt when there is a stall cycle coming! -assign int_condition = (inte_sync_reg && ~exec_stall_reg && ~next_exec_stall && intcon_reg[7]); - // Interrupt must be pending - // Next processor cycle must not be a stall - // GIE bit must be set to issue interrupt - -// Circuit's output signals -assign prog_adr_o = pc_reg; // program ROM address -assign ram_adr_o = ram_adr_node; // data RAM address -assign ram_dat_o = aluout; // data RAM write data -assign ram_we_o = ram_we_reg; // data RAM write enable - -assign aux_adr_o = {aux_adr_hi_reg,aux_adr_lo_reg}; -assign aux_dat_io = (aux_we_reg && clk_en_i)?aluout:{8{1'bZ}}; -assign aux_we_o = aux_we_reg; - -endmodule - - -//`undef STATEBIT_SIZE \ No newline at end of file Index: trunk/srec_to_rs232.pl =================================================================== --- trunk/srec_to_rs232.pl (revision 6) +++ trunk/srec_to_rs232.pl (nonexistent) @@ -1,67 +0,0 @@ -#!/usr/bin/perl -w -print "\nMotorola S-record to rs232_syscon command translator."; -print "\nFilename to translate? "; -$filename = ; -chomp ($filename); -print "\nReading file \"$filename\"\n"; -open (SRECORDFILE,$filename) || - die "\nCan't open \"$filename\" for input.\n"; - -# Handle getting a new extension for the output filename -$i = index($filename,"."); - # If no period is found, simply add the extension to the end. -if ($i < 0) { $i = length($filename); } -substr($filename,$i,4) = ".232"; - -# Open the output file -open (OUTPUTFILE,">".$filename) || - die "\nCan't open \"$filename\" for output.\n"; - -$line_number = 0; -while ($line = ) { - # increment the line number counter - $line_number += 1; - # ignore lines that begin with semicolon - if (index($line,";")==0) { next; } - # Get the position of the start of data - # (Usually there is a colon at the very start of the line...) - $i = index($line,":"); - if ($i < 0) { - print "\nError! No colon found on line: $line_number"; - last; - } - # Get the length of the line - $line_length = hex(substr($line,($i+1),2)); - if ($line_length == 0) { - print "0"; - next; - } - - # Extract the starting address - $line_starting_address = hex(substr($line,($i+3),4)); - - # Extract the data substring - length is in units of bytes, - # but each character is 1/2 byte, so multiply by 2. - $line_data = substr($line,($i+9),($line_length*2)); - - # Send data characters to output file as rs232_syscon commands - # increment by 2 in order to send 1 byte per command... - for ($i=0;$i<($line_length*2);$i+=2) { - $j = $line_starting_address + $i/2; - $j = sprintf "%lx",$j; # Convert address to hexadecimal - $byte = substr($line_data,$i,2); - print OUTPUTFILE "w $j $byte\n"; - } - -# Verbose debug information... -# print "\nline $line_number: starts at $line_starting_address "; -# print "length is $line_length "; -# print "data is $line_data "; - # Print a little period for each line processed... - # (to complement the 0 printed for zero length lines encountered.) - print "."; - } - -#Close all open files -close (SRECORDFILE); -close (OUTPUTFILE); Index: risc16f84/trunk/risc16f84_clk2x.v =================================================================== --- risc16f84/trunk/risc16f84_clk2x.v (nonexistent) +++ risc16f84/trunk/risc16f84_clk2x.v (revision 7) @@ -0,0 +1,963 @@ +//--------------------------------------------------------------------------- +// RISC 16F84 "clk2x" core +// +// This file is part of the "risc_16F84" project. +// http://www.opencores.org/cores/risc_16F84 +// +// +// Description: See description below (which suffices for IP core +// specification document.) +// +// Copyright (C) 1999 Sumio Morioka (original VHDL design version) +// Copyright (C) 2001 John Clayton and OPENCORES.ORG (this Verilog version) +// +// NOTE: This source code is free for educational/hobby use only. It cannot +// be used for commercial purposes without the consent of Microchip +// Technology incorporated. +// +// This source file may be used and distributed without restriction provided +// that this copyright statement is not removed from the file and that any +// derivative work contains the original copyright notice and the associated +// disclaimer. +// +// This source file is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This source is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this source. +// If not, download it from http://www.opencores.org/lgpl.shtml +// +//--------------------------------------------------------------------------- +// +// Author: John Clayton +// Date : January 29, 2002 +// +// (NOTE: Date formatted as day/month/year.) +// Update: 29/01/02 copied this file from memory_sizer.v (pared down). +// Translated the module and signal declarations. +// Transformed the instruction wires to lowercase. +// Transformed the addressing wires to lowercase. +// Update: 31/01/02 Translated the instruction decoder. +// Update: 5/02/02 Determined that stack is simply a circular buffer of +// 8 locations, 13 bits per location. Started translating +// "main_efsm" process. Added all code from piccore.vhd +// into this file for eventual translation. Concluded that +// "stack_full_node" is not needed. +// Update: 6/02/02 Translated the "ram_i_node" if/else precedural assignment. +// Update: 7/02/02 Changed all := to <=, changed all '0' to 0 and '1' to 1. +// Replaced all " downto " with ":". +// Finished translating QRESET state. +// Update: 20/02/02 Replaced all instances of Qreset with QRESET_PP. Also +// replaced other state designations with their new names. +// Finished translating Q1, Q2 states. +// Update: 22/02/02 Translated section 2-4-1-1 (aluout register) +// Update: 27/02/02 Replaced all "or" with "||" in if statements +// Replaced all "and" with "&&" in if statements. +// Replaced all "not" with "~" in if statements. +// Finished translating Q3,Q4 states. +// Translated output signal assignments at end of code. +// Translated interrupt trigger processes. +// Update: 28/02/02 Finished translation of WDT and TMR0 prescaler. +// Trimmed line length to 80 characters throughout. +// Prepared to attempt initial syntax checking. +// Cleaned up some naming conventions, and verified that +// all I/O pins have _i or _o appended in the body of the +// code. +// Update: 03/04/02 Changed "progdata_i" to "prog_dat_i" Also changed +// "progadr_o" to "prog_adr_o" +// Update: 04/04/02 Created new file "risc16f84_lite.v" This file is reduced +// and simplified from the original "risc16f84.v" file. +// Specifically, I am removing EEPROM support, and +// consolidating porta and portb I/O pins so that they +// are bidirectional. +// Update: 04/04/02 Created a new file "risc16f84_small.v" This file is +// further reduced and simplified from "risc16f84_lite.v" +// Specifically, I am removing the prescaler, TMR0 and WDT. +// Also, I am removing support for portb interrupts, leaving +// only rb0/int as an interrupt source. This pin will be +// the only way to wake up from the SLEEP instruction... +// Obviously, the CLEARWDT instruction will no longer do +// anything. +// Update: 05/04/02 Removed the "powerdown_o", "startclk_o" and "clk_o" pins +// from the small design. Also removed "rbpu_o", so if you +// want pullups, you have to add them explicitly in the +// constraints file, and option_reg[7] doesn't control them. +// Update: 08/04/02 Decided to modify "risc16f84_small.v" in order to try for +// more performance (only 2 states per instruction!) +// The new file is called "risc16f84_clk2x.v" The resulting +// code was synthesized, but not tested yet. +// Update: 11/04/02 Decided to remove porta and portb from this unit, and add +// instead an auxiliary bus, which is intended to allow I/O +// using an indirect approach, similar to using the FSR. +// However, the aux_adr_o is 16 bits wide, so that larger +// RAM may be accessed indirectly by the processor... The use +// of FSR for this purpose proved undesirable, since any new +// page of RAM contains "holes" to accomodate the registers +// in the first 12 locations (including FSR!) so that large +// contiguous blocks of memory could not be accessed in an +// effective way. This auxiliary bus solves that problem. +// Since this processor is implemented inside of an FPGA, +// and it is not a goal to maintain compatibility with +// existing libraries of code, there is no need to maintain +// porta and portb in the hardware. +// The aux_adr_lo and aux_adr_hi registers are located at +// 88h and 89h, and the aux_dat_io location is decoded at +// 08h. +// Also, changed to using "ram_we_o" instead of "readram_o" +// and "writeram_o" +// Update: 16/04/02 Added clock enable signal, for processor single stepping. +// "aux_dat_io" is only driven when "clk_en_i" is high... +// Update: 17/04/02 Removed "reset_condition" and moved "inc_pc_node" out of +// the clocking area, making it non-registered. In fact, I +// moved everything other than the state machine out of the +// clocked logic section. Changed "aluout_reg" to "aluout" +// since it is no longer registered. +// Update: 26/04/02 Fixed bug in aluout logic. The AND and OR functions were +// coded with logical AND/OR instead of bitwise AND/OR! +// Update: 26/04/02 Changed location of aux_adr_lo and aux_adr_hi registers +// to 05h and 06h, respectively. This was done to save +// code space because when using the aux data bus, no bank +// switching is necessary since they will now reside in the +// same bank. +// Update: 01/05/02 Fixed another bug -- the rrf and rlf instructions were +// coded incorrectly. +// Update: 03/05/02 Fixed another bug -- the carry bit was incorrect (the +// problem was discovered while performing SUBWF X,W where +// W contained 0 and X contained 1. (1-0). The logic for +// the carry bit appears to have been incorrect even in +// the original VHDL code by Sumio Morioka. +// Update: 11/18/02 Fixed bug in PCL addressing mode (near line 791) +// Removed parameters associated with WDT. +// Update: 11/25/02 Re-wrote much of the main FSM. Attempted to generate logic +// to recognize the falling edge of an interrupt, and was +// unsuccessful (not simulation, actual hardware tests.) +// Realized that falling edge interrupt can be equivalent to +// rising edge interrupt with a NOT gate on the signal. Since +// NOTs are practically free inside of an FPGA, decided to +// abandon the negative edge aspect of recognizing interrupts. +// Therefore, removed the "option_reg" since it is no longer +// needed in this design. +// Update: 08/08/03 Fixed a mathematical error, which was introduced by the bug +// fix of 03/05/02. The fix of 03/05/02 correctly generated the +// C bit for subtraction of zero, but unfortunately it introduced +// an error such that all subtraction results were off by 1. +// Obviously, this was unacceptable, and I think it has been fixed +// by the new signals "c_subtract_zero" and "c_dig_subtract_zero" +// Update: 10/24/05 Added code patches to fix interrupt bug and status flag updates +// when using literal value of 0x03. These bugs were reported by +// an opencores.org user. Added three "disable_status_x" signals. +// Modified file still needs to be tested. +// +// Description +//--------------------------------------------------------------------------- +// This logic module implements a small RISC microcontroller, with functions +// and instruction set very similar to those of the Microchip 16F84 chip. +// This work is a translation (from VHDL to Verilog) of the "CQPIC" design +// published in 1999 by Sumio Morioka of Japan, and published in the December +// 1999 issue of "Transistor Gijutsu Magazine." The translation was performed +// by John Clayton, without the use of any translation tools. +// +// Original version used as basis for translation: CQPIC version 1.00b +// (December 10, 2000) +// +// Further revisions and re-writing have been completed on this code by John +// Clayton. The interrupt mechanism has been completely re-done, and the +// way in which the program counter is generated is expressed in a new way. +// +// In the comments, a "cycle" is defined as a processor cycle of 2 states. +// Thus, passing through states Q2_PP and Q4_PP completes one cycle. +// The numbers "1-3" and so forth are left from the comments in the original +// source code used as the basis of the translation. +//--------------------------------------------------------------------------- + +`define STATEBIT_SIZE 2 // Size of state machine register (bits) + + +module risc16f84_clk2x ( + prog_dat_i, // [13:0] ROM read data + prog_adr_o, // [12:0] ROM address + ram_dat_i, // [7:0] RAM read data + ram_dat_o, // [7:0] RAM write data + ram_adr_o, // [8:0] RAM address; ram_adr[8:7] indicates RAM-BANK + ram_we_o, // RAM write strobe (H active) + aux_adr_o, // [15:0] Auxiliary address bus + aux_dat_io, // [7:0] Auxiliary data bus (tri-state bidirectional) + aux_we_o, // Auxiliary write strobe (H active) + int0_i, // PORT-B(0) INT + reset_i, // Power-on reset (H active) + clk_en_i, // Clock enable for all clocked logic + clk_i // Clock input +); + + +// You can change the following parameters as you would like +parameter STACK_SIZE_PP = 8; // Size of PC stack +parameter LOG2_STACK_SIZE_PP = 3; // Log_2(stack_size) + +// State definitions for state machine, provided as parameters to allow +// for redefinition of state values by the instantiator if desired. +parameter Q2_PP = 2'b00; // state Q2 +parameter Q4_PP = 2'b01; // state Q4 +parameter QINT_PP = 2'b10; // interrupt state (substitute for Q4) +parameter QSLEEP_PP = 2'b11; // sleep state + + +// I/O declarations + + // program ROM data bus/address bus +input [13:0] prog_dat_i; // ROM read data +output [12:0] prog_adr_o; // ROM address + + // data RAM data bus/address bus/control signals +input [7:0] ram_dat_i; // RAM read data +output [7:0] ram_dat_o; // RAM write data +output [8:0] ram_adr_o; // RAM address; ram_adr[8:7] indicates RAM-BANK +output ram_we_o; // RAM write strobe (H active) + + // auxiliary data bus/address bus/control signals +output [15:0] aux_adr_o; // AUX address bus +inout [7:0] aux_dat_io; // AUX data bus +output aux_we_o; // AUX write strobe (H active) + + // interrupt input +input int0_i; // INT + + // CPU reset +input reset_i; // Power-on reset (H active) + + // CPU clock +input clk_en_i; // Clock enable input +input clk_i; // Clock input + + +// Internal signal declarations + + // User registers +reg [7:0] w_reg; // W +reg [12:0] pc_reg; // PCH/PCL -- Address currently being fetched +reg [12:0] old_pc_reg; // Address fetched previous to this one. +reg [7:0] status_reg; // STATUS +reg [7:0] fsr_reg; // FSR +reg [4:0] pclath_reg; // PCLATH +reg [7:0] intcon_reg; // INTCON +reg [7:0] aux_adr_hi_reg; // AUX address high byte +reg [7:0] aux_adr_lo_reg; // AUX address low byte + + // Internal registers for controlling instruction execution +reg [13:0] inst_reg; // Holds fetched op-code/operand +reg [7:0] aluinp1_reg; // data source (1 of 2) +reg [7:0] aluinp2_reg; // data source (2 of 2) +reg exec_stall_reg; // if H (i.e. after GOTO etc), stall execution. + + // Stack + // stack (array of data-registers) +reg [12:0] stack_reg [STACK_SIZE_PP-1:0]; + // stack pointer +reg [LOG2_STACK_SIZE_PP-1:0] stack_pnt_reg; +wire [12:0] stack_top; // More compatible with sensitivity list than + // "stack_reg[stack_pnt_reg]" + + // Interrupt registers/nodes +wire int_condition; // Indicates that an interrupt should be recognized +wire intrise; // High indicates edge was detected +reg intrise_reg; // detect positive edge of PORT-B inputs + // Synchronizer for interrupt +reg inte_sync_reg; + + // State register +reg [`STATEBIT_SIZE-1:0] state_reg; +reg [`STATEBIT_SIZE-1:0] next_state_node; + + // Result of decoding instruction -- only 1 is active at a time +wire inst_addlw; +wire inst_addwf; +wire inst_andlw; +wire inst_andwf; +wire inst_bcf; +wire inst_bsf; +wire inst_btfsc; +wire inst_btfss; +wire inst_call; +wire inst_clrf; +wire inst_clrw; +wire inst_comf; +wire inst_decf; +wire inst_decfsz; +wire inst_goto; +wire inst_incf; +wire inst_incfsz; +wire inst_iorlw; +wire inst_iorwf; +wire inst_movlw; +wire inst_movf; +wire inst_movwf; +wire inst_retfie; +wire inst_retlw; +wire inst_ret; +wire inst_rlf; +wire inst_rrf; +wire inst_sleep; +wire inst_sublw; +wire inst_subwf; +wire inst_swapf; +wire inst_xorlw; +wire inst_xorwf; + + // Result of calculating RAM access address +wire [8:0] ram_adr_node; // RAM access address + + // These wires indicate accesses to special registers... + // Only 1 is active at a time. +wire addr_pcl; +wire addr_stat; +wire addr_fsr; +wire addr_pclath; +wire addr_intcon; +wire addr_aux_adr_lo; +wire addr_aux_adr_hi; +wire addr_aux_dat; +wire addr_sram; + + // Other output registers (for removing hazards) +reg ram_we_reg; // data-sram write strobe +reg aux_we_reg; // AUX write strobe + + + // Signals used in "main_efsm" procedure + // (Intermediate nodes used for resource sharing.) +wire [7:0] ram_i_node; // result of reading RAM/Special registers +wire [7:0] mask_node; // bit mask for logical operations +wire [8:0] add_node; // result of 8bit addition +wire [4:0] addlow_node; // result of low-4bit addition +wire aluout_zero_node; // H if ALUOUT = 0 + +reg [12:0] next_pc_node; // value of next PC +reg [7:0] aluout; // result of calculation +reg writew_node; // H if destination is W register +reg writeram_node; // H if destination is RAM/Special registers +reg c_subtract_zero; // High for special case of C bit, when subtracting zero +reg c_dig_subtract_zero; // High for special case of C bit, when subtracting zero + +wire next_exec_stall; + // Three signals used to disable status flag updates. Fixes bug when literal 0x03 is used. +wire disable_status_z; +wire disable_status_c; +wire disable_status_dc; + +//-------------------------------------------------------------------------- +// Instantiations +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- +// Functions & Tasks +//-------------------------------------------------------------------------- + +//-------------------------------------------------------------------------- +// Module code +//-------------------------------------------------------------------------- + +// This represents the instruction fetch from program memory. +// inst_reg[13:0] stores the instruction. This happens at the end of Q4. +// So the memory access time is one processor cycle (2 clocks!) minus +// the setup-time of this register, and minus the delay to drive the +// address out onto the prog_adr_o bus. +always @(posedge clk_i) +begin + if (reset_i) inst_reg <= 0; + else if (clk_en_i && (state_reg == Q4_PP)) inst_reg <= prog_dat_i; +end + +// NOTE: There is an extra "15th" bit of inst_reg, which represents an +// interrupt execution cycle. This is included in inst_reg so that when +// an interrupt instruction is executing, it effectively "pre-empts" the +// other instructions. +// The fifteenth bit, inst_reg[14], is set by the interrupt logic. + +// Decode OPcode (see pp.54 of PIC16F84 data sheet) +// only 1 signal of the following signals will be '1' +assign inst_call = (inst_reg[13:11] == 3'b100 ); +assign inst_goto = (inst_reg[13:11] == 3'b101 ); +assign inst_bcf = (inst_reg[13:10] == 4'b0100 ); +assign inst_bsf = (inst_reg[13:10] == 4'b0101 ); +assign inst_btfsc = (inst_reg[13:10] == 4'b0110 ); +assign inst_btfss = (inst_reg[13:10] == 4'b0111 ); +assign inst_movlw = (inst_reg[13:10] == 4'b1100 ); +assign inst_retlw = (inst_reg[13:10] == 4'b1101 ); +assign inst_sublw = (inst_reg[13:9] == 5'b11110 ); +assign inst_addlw = (inst_reg[13:9] == 5'b11111 ); +assign inst_iorlw = (inst_reg[13:8] == 6'b111000 ); +assign inst_andlw = (inst_reg[13:8] == 6'b111001 ); +assign inst_xorlw = (inst_reg[13:8] == 6'b111010 ); +assign inst_subwf = (inst_reg[13:8] == 6'b000010 ); +assign inst_decf = (inst_reg[13:8] == 6'b000011 ); +assign inst_iorwf = (inst_reg[13:8] == 6'b000100 ); +assign inst_andwf = (inst_reg[13:8] == 6'b000101 ); +assign inst_xorwf = (inst_reg[13:8] == 6'b000110 ); +assign inst_addwf = (inst_reg[13:8] == 6'b000111 ); +assign inst_movf = (inst_reg[13:8] == 6'b001000 ); +assign inst_comf = (inst_reg[13:8] == 6'b001001 ); +assign inst_incf = (inst_reg[13:8] == 6'b001010 ); +assign inst_decfsz = (inst_reg[13:8] == 6'b001011 ); +assign inst_rrf = (inst_reg[13:8] == 6'b001100 ); +assign inst_rlf = (inst_reg[13:8] == 6'b001101 ); +assign inst_swapf = (inst_reg[13:8] == 6'b001110 ); +assign inst_incfsz = (inst_reg[13:8] == 6'b001111 ); +assign inst_movwf = (inst_reg[13:7] == 7'b0000001 ); +assign inst_clrw = (inst_reg[13:7] == 7'b0000010 ); +assign inst_clrf = (inst_reg[13:7] == 7'b0000011 ); +assign inst_ret = (inst_reg[13:0] == 14'b00000000001000); +assign inst_retfie = (inst_reg[13:0] == 14'b00000000001001); +assign inst_sleep = (inst_reg[13:0] == 14'b00000001100011); + + +// Calculate RAM access address (see pp.19 of PIC16F84 data sheet) + + // if "d"=0, indirect addressing is used, so RAM address is BANK+FSR + // otherwise, RAM address is BANK+"d" + // (see pp.19 of PIC16F84 data sheet) +assign ram_adr_node = (inst_reg[6:0]==0)?{status_reg[7],fsr_reg[7:0]}: + {status_reg[6:5],inst_reg[6:0]}; + + // check if this is an access to external RAM or not +assign addr_sram = (ram_adr_node[6:0] > 7'b0001011); //0CH-7FH,8CH-FFH + + // check if this is an access to special register or not + // only 1 signal of the following signals will be '1' +assign addr_pcl = (ram_adr_node[6:0] == 7'b0000010); // 02H, 82H +assign addr_stat = (ram_adr_node[6:0] == 7'b0000011); // 03H, 83H +assign addr_fsr = (ram_adr_node[6:0] == 7'b0000100); // 04H, 84H +assign addr_aux_dat = (ram_adr_node[7:0] == 8'b00001000); // 08H +assign addr_pclath = (ram_adr_node[6:0] == 7'b0001010); // 0AH, 8AH +assign addr_intcon = (ram_adr_node[6:0] == 7'b0001011); // 0BH, 8BH +assign addr_aux_adr_lo = (ram_adr_node[7:0] == 8'b00000101); // 05H +assign addr_aux_adr_hi = (ram_adr_node[7:0] == 8'b00000110); // 06H + +// construct bit-mask for logical operations and bit tests +assign mask_node = 1 << inst_reg[9:7]; + +// disable write access for status flags +assign disable_status_z = (inst_addwf || inst_andwf || inst_clrf || + inst_clrw || inst_comf || inst_decf || + inst_incf || inst_iorwf || inst_movf || + inst_subwf || inst_xorwf || inst_addlw || + inst_andlw || inst_iorlw || inst_iorlw || + inst_sublw || inst_xorlw) ? 1:0; +assign disable_status_c = (inst_addwf || inst_subwf || inst_rlf || + inst_rrf || inst_addlw || inst_sublw ) ? 1:0; +assign disable_status_dc = (inst_addwf || inst_subwf || inst_addlw || + inst_sublw ) ? 1:0; + + +// Create the exec_stall signal, based on the contents of the currently +// executing instruction (inst_reg). next_exec_stall reflects the state +// to assign to exec_stall following the conclusion of the next Q4 state. +// All of these instructions cause an execution stall in the next cycle +// because they modify the program counter, and a new value is presented +// for fetching during the stall cycle, during which time no instruction +// should be executed. +// +// The conditional instructions are given along with their conditions for +// execution. If the conditions are not met, there is no stall and nothing +// to execute. +assign next_exec_stall = ( + inst_goto + || inst_call + || inst_ret + || inst_retlw + || inst_retfie + || ( + (inst_btfsc || inst_decfsz || inst_incfsz) + && aluout_zero_node + ) + || (inst_btfss && ~aluout_zero_node) + || (addr_pcl && writeram_node) + ); +always @(posedge clk_i) +begin + if (reset_i) exec_stall_reg <= 0; + else if (clk_en_i && (state_reg == QINT_PP)) exec_stall_reg <= 1; + else if (clk_en_i && (state_reg == Q4_PP)) + exec_stall_reg <= (next_exec_stall && ~exec_stall_reg); + // exec stall should never be generated during a stall cycle, because + // a stall cycle doesn't execute anything... +end + +assign stack_top = stack_reg[stack_pnt_reg]; +// Formulate the next pc_reg value (the program counter.) +// During stall cycles, the pc is simply incremented... +always @( + pc_reg + or pclath_reg + or aluout + or stack_pnt_reg + or stack_top + or inst_ret + or inst_retlw + or inst_retfie + or inst_goto + or inst_call + or inst_reg + or writeram_node + or addr_pcl + or exec_stall_reg + ) +begin + if (~exec_stall_reg &&(inst_ret || inst_retlw || inst_retfie)) + next_pc_node <= stack_top; + else if (~exec_stall_reg &&(inst_goto || inst_call)) + next_pc_node <= {pclath_reg[4:3],inst_reg[10:0]}; + else if (~exec_stall_reg && (writeram_node && addr_pcl)) + // PCL is data-destination, but update the entire PC. + next_pc_node <= {pclath_reg[4:0],aluout}; + else + next_pc_node <= pc_reg + 1; +end + +// Set the program counter +// If the sleep instruction is executing, then the PC is not allowed to be +// updated, since the processor will "freeze" and the instruction being fetched +// during the sleep instruction must be executed upon wakeup interrupt. +// Obviously, if the PC were to change at the end of the sleep instruction, then +// a different (incorrect) address would be fetched during the sleep time. +always @(posedge clk_i) +begin + if (reset_i) begin + pc_reg <= 0; + old_pc_reg <= 0; + end + else if (clk_en_i && (state_reg == QINT_PP)) + begin + old_pc_reg <= pc_reg; + pc_reg <= 4; + end + else if (clk_en_i && ~inst_sleep && (state_reg == Q4_PP)) + begin + old_pc_reg <= pc_reg; + pc_reg <= next_pc_node; + end +end + +// 1. Intermediate nodes for resource sharing + +// Tri-state drivers instead of a huge selector... It produces smaller +// results, and runs faster. +assign ram_i_node = (addr_sram) ?ram_dat_i:8'bZ; +assign ram_i_node = (addr_pcl) ?pc_reg[7:0]:8'bZ; +assign ram_i_node = (addr_stat) ?status_reg:8'bZ; +assign ram_i_node = (addr_fsr) ?fsr_reg:8'bZ; +assign ram_i_node = (addr_aux_dat) ?aux_dat_io:8'bZ; +assign ram_i_node = (addr_pclath) ?{3'b0,pclath_reg}:8'bZ; +assign ram_i_node = (addr_intcon) ?intcon_reg:8'bZ; +assign ram_i_node = (addr_aux_adr_lo) ?aux_adr_lo_reg:8'bZ; +assign ram_i_node = (addr_aux_adr_hi) ?aux_adr_hi_reg:8'bZ; + +// 1-3. Adder (ALU) +// full 8bit-addition, with carry in/out. +// Note that "temp" and "dtemp" are intended to be thrown away. +// Also, addlow_node[3:0] are thrown away. +// Even though they are assigned, they should never be used. +assign add_node = {1'b0,aluinp1_reg} + + {1'b0,aluinp2_reg}; +// lower 4bit-addition +assign addlow_node = {1'b0,aluinp1_reg[3:0]} + + {1'b0,aluinp2_reg[3:0]}; + +// 1-4. Test if aluout = 0 +assign aluout_zero_node = (aluout == 0)?1:0; + +// 1-5. Determine destination +always @( + inst_reg + or inst_movwf + or inst_bcf + or inst_bsf + or inst_clrf + or inst_movlw + or inst_addlw + or inst_sublw + or inst_andlw + or inst_iorlw + or inst_xorlw + or inst_retlw + or inst_clrw + or inst_movf + or inst_swapf + or inst_addwf + or inst_subwf + or inst_andwf + or inst_iorwf + or inst_xorwf + or inst_decf + or inst_incf + or inst_rlf + or inst_rrf + or inst_decfsz + or inst_incfsz + or inst_comf + ) +begin + if (inst_movwf || inst_bcf || inst_bsf || inst_clrf) + begin + writew_node <= 0; + writeram_node <= 1; + end + else if ( inst_movlw || inst_addlw || inst_sublw || inst_andlw + || inst_iorlw || inst_xorlw || inst_retlw || inst_clrw) + begin + writew_node <= 1; + writeram_node <= 0; + end + else if ( inst_movf || inst_swapf || inst_addwf || inst_subwf + || inst_andwf || inst_iorwf || inst_xorwf || inst_decf + || inst_incf || inst_rlf || inst_rrf || inst_decfsz + || inst_incfsz || inst_comf) + begin + writew_node <= ~inst_reg[7]; // ("d" field of fetched instruction) + writeram_node <= inst_reg[7]; // ("d" field of fetched instruction) + end + else + begin + writew_node <= 0; + writeram_node <= 0; + end +end // End of determine destination logic + + + + +// 2-4-1. Calculation and store result into alu-output register + +always @( + add_node + or aluinp1_reg + or aluinp2_reg + or status_reg + or inst_reg + or inst_movwf + or inst_bcf + or inst_bsf + or inst_btfsc + or inst_btfss + or inst_clrf + or inst_addlw + or inst_sublw + or inst_andlw + or inst_iorlw + or inst_xorlw + or inst_retlw + or inst_clrw + or inst_swapf + or inst_addwf + or inst_subwf + or inst_andwf + or inst_iorwf + or inst_xorwf + or inst_decf + or inst_incf + or inst_rlf + or inst_rrf + or inst_decfsz + or inst_incfsz + or inst_comf + ) +begin + // 2-4-1-1. Set aluout register + // Rotate left + if (inst_rlf) + aluout <= {aluinp1_reg[6:0],status_reg[0]}; + // Rotate right + else if (inst_rrf) + aluout <= {status_reg[0],aluinp1_reg[7:1]}; + // Swap nibbles + else if (inst_swapf) + aluout <= {aluinp1_reg[3:0],aluinp1_reg[7:4]}; + // Logical inversion + else if (inst_comf) + aluout <= ~aluinp1_reg; + // Logical AND, bit clear/bit test + else if ( inst_andlw || inst_andwf || inst_bcf || inst_btfsc + || inst_btfss) + aluout <= (aluinp1_reg & aluinp2_reg); + // Logical OR, bit set + else if (inst_bsf || inst_iorlw || inst_iorwf) + aluout <= (aluinp1_reg | aluinp2_reg); + // Logical XOR + else if (inst_xorlw || inst_xorwf) + aluout <= (aluinp1_reg ^ aluinp2_reg); + // Addition, Subtraction, Increment, Decrement + else if ( inst_addlw || inst_addwf || inst_sublw || inst_subwf + || inst_decf || inst_decfsz || inst_incf || inst_incfsz) + aluout <= add_node[7:0]; + // Pass through + else aluout <= aluinp1_reg; +end + + +// MAIN EFSM: description of register value changes in each clock cycle +always @(posedge clk_i) +begin + // Assign reset (default) values of registers + if (reset_i) + begin + status_reg[7:5] <= 3'b0; + pclath_reg <= 0; // 0 + intcon_reg[7:1] <= 7'b0; + aux_adr_lo_reg <= 0; + aux_adr_hi_reg <= 0; + ram_we_reg <= 0; + status_reg[4] <= 1; // /T0 = 1 + status_reg[3] <= 1; // /PD = 1 + stack_pnt_reg <= 0; // Reset stack pointer + end // End of reset assignments + else if (~exec_stall_reg && clk_en_i) + begin // Execution ceases during a stall cycle. + if (state_reg == Q2_PP) // 2-3. Q2 cycle + begin + // 2-3-1. Read data-RAM and store values to alu-input regs + // 2-3-1-1. Set aluinp1 register (source #1) + if ( inst_movf || inst_swapf || inst_addwf || inst_subwf + || inst_andwf || inst_iorwf || inst_xorwf || inst_decf + || inst_incf || inst_rlf || inst_rrf || inst_bcf + || inst_bsf || inst_btfsc || inst_btfss || inst_decfsz + || inst_incfsz || inst_comf) + + aluinp1_reg <= ram_i_node; // RAM/Special registers + else + if ( inst_movlw || inst_addlw || inst_sublw || inst_andlw + || inst_iorlw || inst_xorlw || inst_retlw) + aluinp1_reg <= inst_reg[7:0]; // Immediate value ("k") + else + if ( inst_clrf || inst_clrw) aluinp1_reg <= 0; // 0 + else aluinp1_reg <= w_reg; // W register + + // 2-3-1-2. Set aluinp2 register (source #2) + c_subtract_zero <= 0; // default to non-special case + c_dig_subtract_zero <= 0; // default to non-special case + if (inst_decf || inst_decfsz) aluinp2_reg <= -1; // for decr. + else if (inst_incf || inst_incfsz) aluinp2_reg <= 1; // for incr. + // -1 * W register (for subtract) + else if (inst_sublw || inst_subwf) + begin + aluinp2_reg <= ~w_reg + 1; + c_subtract_zero <= (w_reg == 0); // Indicate special case + c_dig_subtract_zero <= (w_reg[3:0] == 0); // Indicate special case + end + // operation of BCF: AND with inverted mask ("1..101..1") + // mask for BCF: value of only one position is 0 + else if (inst_bcf) aluinp2_reg <= ~mask_node; + // operation of BSF: OR with mask_node ("0..010..0") + // operation of FSC and FSS: AND with mask_node, compare to 0 + else if (inst_btfsc || inst_btfss || inst_bsf) + aluinp2_reg <= mask_node; + else aluinp2_reg <= w_reg; // W register + + // 2-3-1-3. Set stack pointer register (pop stack) + if (inst_ret || inst_retlw || inst_retfie) + stack_pnt_reg <= stack_pnt_reg - 1; // cycles 3,2,1,0,7,6... + + // 2-4-1-3. Set data-SRAM write enable (hazard-free) + // Set the write enables depending on the destination. + // (These have been implemented as registers to avoid glitches? + // It is not known to me (John Clayton) whether any glitches would + // really occur. It might be possible to generate these signals + // using combinational logic only, without using registers! + ram_we_reg <= (writeram_node && addr_sram); + aux_we_reg <= (writeram_node && addr_aux_dat); + end // End of Q2 state + + //--------------------------------------------------------------------- + + else if (state_reg == QINT_PP) // Interrupt execution (instead of Q4_PP) + begin + // PORT-B0 INT + intcon_reg[1] <= 1; // set INTF + intcon_reg[7] <= 0; // clear GIE + stack_reg[stack_pnt_reg] <= old_pc_reg; // Push old PC + stack_pnt_reg <= stack_pnt_reg + 1; // increment stack pointer + // The old PC is pushed, so that the pre-empted instruction can be + // restarted later, when the retfie is executed. + end + + //--------------------------------------------------------------------- + + else if (state_reg == Q4_PP) // Execution & writing of results. + begin + + if (inst_call) + begin + stack_reg[stack_pnt_reg] <= pc_reg; // Push current PC + stack_pnt_reg <= stack_pnt_reg + 1; // increment stack pointer + end + + if (inst_retfie) // "return from interrupt" instruction + begin + intcon_reg[7] <= 1; // Set GIE + end + + // 2-4-1-2. Set C flag and DC flag + if (inst_addlw || inst_addwf || inst_sublw || inst_subwf) + begin + // c_dig_subtract_zero and c_subtract_zero are used to take care of the + // special case when subtracting zero, where the carry bit should be 1 + // (meaning no borrow). It is explicitly set by these signals during + // that condition. See 16F84 datasheet, page 8 for further information + // about the C bit. + status_reg[1] <= addlow_node[4] || c_dig_subtract_zero; // DC flag + status_reg[0] <= add_node[8] || c_subtract_zero; // C flag + end + else if (inst_rlf) status_reg[0] <= aluinp1_reg[7]; // C flag + else if (inst_rrf) status_reg[0] <= aluinp1_reg[0]; // C flag + + // 2-5-2. Store calculation result into destination, + // 2-5-2-1. Set W register + + if (writew_node) w_reg <= aluout; // write W reg + + + // 2-5-2-2. Set data RAM/special registers, + if (writeram_node) + begin + if (addr_stat) + begin + status_reg[7:5] <= aluout[7:5]; // write IRP,RP1,RP0 + // status(4),status(3)...unwritable, see below (/PD,/T0 part) + if( ~disable_status_c ) status_reg[0] <= aluout[0]; // write C + if( ~disable_status_dc ) status_reg[1] <= aluout[1]; // write DC + end + if (addr_fsr) fsr_reg <= aluout; // write FSR + if (addr_pclath) pclath_reg <= aluout[4:0]; // write PCLATH + if (addr_intcon) intcon_reg <= aluout; // write INTCON + if (addr_aux_adr_lo) aux_adr_lo_reg <= aluout; // write AUX low + if (addr_aux_adr_hi) aux_adr_hi_reg <= aluout; // write AUX high + end + + // 2-5-2-3. Set/clear Z flag. + if (addr_stat && ~disable_status_z) status_reg[2] <= aluout[2]; + else if ( inst_addlw || inst_addwf || inst_andlw || inst_andwf + || inst_clrf || inst_clrw || inst_comf || inst_decf + || inst_incf || inst_movf || inst_sublw || inst_subwf + || inst_xorlw || inst_xorwf || inst_iorlw || inst_iorwf ) + status_reg[2] <= aluout_zero_node; // Z=1 if result == 0 + + // 2-5-3. Clear RAM write enables (hazard-free) + ram_we_reg <= 0; + aux_we_reg <= 0; + + end // End of Q4 state + end // End of "if (~exec_stall_reg)" +end // End of process + + +// Calculation of next processor state. +// (Not including reset conditions, which are covered by the clocked logic, +// which also includes a "global clock enable." +always @( + state_reg + or inst_sleep + or inte_sync_reg + or exec_stall_reg + or int_condition + ) +begin + case (state_reg) + Q2_PP : if (int_condition) next_state_node <= QINT_PP; + else next_state_node <= Q4_PP; + Q4_PP : if (~exec_stall_reg && inst_sleep) next_state_node <= QSLEEP_PP; + else next_state_node <= Q2_PP; + QINT_PP : next_state_node <= Q2_PP; + QSLEEP_PP : if (inte_sync_reg) next_state_node <= Q2_PP; + else next_state_node <= QSLEEP_PP; + // Default condition provided for convention and completeness + // only. Logically, all of the conditions are already covered. + default : next_state_node <= Q2_PP; + endcase +end + + +// Clocked state transitions, based upon dataflow (non-clocked logic) in +// the previous always block. +always @(posedge clk_i) +begin + if (reset_i) state_reg <= Q2_PP; + else if (clk_en_i) state_reg <= next_state_node; +end // End of process + + +// Detect external interrupt requests +// You can code multiple interrupts if you wish, or use the single interrupt +// provided and simply have the interrupt service routine (ISR) check to find +// out the source of the interrupt, by or-ing together all of the interrupt +// sources and providing a readable register of their values at the time +// the interrupt occurred. +// +// When an interrupt is recognized by the processor, this is signified by +// entering "QINT_PP," which is treated like an executable instruction. +// The interrupt instruction can only be executed when not in a stall condition. +// It simply "pre-empts" the instruction that would have been executed during +// that cycle. Then, when retfie is executed, the pre-empted instruction is +// re-started (the stall cycle of the retfie is when the address of the +// instruction being re-started is fetched.) +// +// I was unable to obtain correct operation for capturing the negative edge, +// so I am discarding it. If one really needs to generate an interrupt on the +// falling edge, just use an inverted version of the signal (the inversion is +// often "free" inside of an FPGA anyhow.) +// +// Upon further testing, I discovered that even the rising edge "trigger" was not +// really truly an edge detection, it was more like a "set-reset" flip flop +// type of behavior. Rather than mess around with it any more, I am implementing +// a clocked "poor man's rising edge detector." +// Capture the rising edge of the interrupt input... This part is self clearing. +// It also means that the interrupt must last longer than one clock cycle in +// order to be properly recognized. (It is "pseudo edge triggered", not a true +// rising edge trigger.) +// When the interrupt is recognized, inte_sync_reg is cleared. + + +always @(posedge clk_i) +begin + if (clk_en_i) intrise_reg <= int0_i; +end // process +assign intrise = (int0_i && ~intrise_reg); + +// The inte_sync_reg signal is used for waking up from SLEEP. +// (this flip flop is also a synchronizer to minimize the +// possibility of metastability due to changes at the input +// occurring at the same time as the processor clock edge...) +// It might be possible to eliminate this step, and issue the interrupt +// directly without this intermediate synchronizer flip-flop. +always @(posedge clk_i) +begin + if (reset_i || (state_reg == QINT_PP)) inte_sync_reg <= 0; + else if (clk_en_i && intrise && intcon_reg[4]) inte_sync_reg <= 1; +end + +// Issue an interrupt when the interrupt is present. +// Also, do not issue an interrupt when there is a stall cycle coming! +assign int_condition = (inte_sync_reg && ~exec_stall_reg && ~next_exec_stall && intcon_reg[7]); + // Interrupt must be pending + // Next processor cycle must not be a stall + // GIE bit must be set to issue interrupt + +// Circuit's output signals +assign prog_adr_o = pc_reg; // program ROM address +assign ram_adr_o = ram_adr_node; // data RAM address +assign ram_dat_o = aluout; // data RAM write data +assign ram_we_o = ram_we_reg; // data RAM write enable + +assign aux_adr_o = {aux_adr_hi_reg,aux_adr_lo_reg}; +assign aux_dat_io = (aux_we_reg && clk_en_i)?aluout:{8{1'bZ}}; +assign aux_we_o = aux_we_reg; + +endmodule + + +//`undef STATEBIT_SIZE \ No newline at end of file Index: risc16f84/trunk/documentation.shtml =================================================================== --- risc16f84/trunk/documentation.shtml (nonexistent) +++ risc16f84/trunk/documentation.shtml (revision 7) @@ -0,0 +1,17 @@ +Project: risc16f84

+Overview | +People | +Documentation | +Download | +Opencores Mail list | +Contact me
+

Documentation

+The data sheet for a 16F84A microcontroller from Microchip contains a superset of all of the instruction formats supported in "risc16f84_clk2x.v" For example, the "CLRWDT" instruction is not supported in "risc16f84_clk2x.v" because there is no watch dog timer. Also, ports A and B do not exist in "risc16f84_clk2x.v" so the user should be aware that this is NOT a fully compatible PIC type microcontroller. Much of the existing PIC code WILL NOT RUN on this microcontroller design because of these incompatibilities, and many libraries of code provided with PIC compilers will depend upon features that are not supported in this module. +However, new code which is written specifically for the "risc16f84_clk2x.v" design will run just fine. +

+

Interrupts have not been tested at this time.

+

In order to get up and running with this module, please examine the example code which shows how the module was used during testing. Also, the code is full of good comments, and there is a fairly detailed explanation of the working of the module in the file header.

+

+ + + Index: risc16f84/trunk/srec_to_rs232.pl =================================================================== --- risc16f84/trunk/srec_to_rs232.pl (nonexistent) +++ risc16f84/trunk/srec_to_rs232.pl (revision 7) @@ -0,0 +1,67 @@ +#!/usr/bin/perl -w +print "\nMotorola S-record to rs232_syscon command translator."; +print "\nFilename to translate? "; +$filename = ; +chomp ($filename); +print "\nReading file \"$filename\"\n"; +open (SRECORDFILE,$filename) || + die "\nCan't open \"$filename\" for input.\n"; + +# Handle getting a new extension for the output filename +$i = index($filename,"."); + # If no period is found, simply add the extension to the end. +if ($i < 0) { $i = length($filename); } +substr($filename,$i,4) = ".232"; + +# Open the output file +open (OUTPUTFILE,">".$filename) || + die "\nCan't open \"$filename\" for output.\n"; + +$line_number = 0; +while ($line = ) { + # increment the line number counter + $line_number += 1; + # ignore lines that begin with semicolon + if (index($line,";")==0) { next; } + # Get the position of the start of data + # (Usually there is a colon at the very start of the line...) + $i = index($line,":"); + if ($i < 0) { + print "\nError! No colon found on line: $line_number"; + last; + } + # Get the length of the line + $line_length = hex(substr($line,($i+1),2)); + if ($line_length == 0) { + print "0"; + next; + } + + # Extract the starting address + $line_starting_address = hex(substr($line,($i+3),4)); + + # Extract the data substring - length is in units of bytes, + # but each character is 1/2 byte, so multiply by 2. + $line_data = substr($line,($i+9),($line_length*2)); + + # Send data characters to output file as rs232_syscon commands + # increment by 2 in order to send 1 byte per command... + for ($i=0;$i<($line_length*2);$i+=2) { + $j = $line_starting_address + $i/2; + $j = sprintf "%lx",$j; # Convert address to hexadecimal + $byte = substr($line_data,$i,2); + print OUTPUTFILE "w $j $byte\n"; + } + +# Verbose debug information... +# print "\nline $line_number: starts at $line_starting_address "; +# print "length is $line_length "; +# print "data is $line_data "; + # Print a little period for each line processed... + # (to complement the 0 printed for zero length lines encountered.) + print "."; + } + +#Close all open files +close (SRECORDFILE); +close (OUTPUTFILE); Index: risc16f84/trunk/people.shtml =================================================================== --- risc16f84/trunk/people.shtml (nonexistent) +++ risc16f84/trunk/people.shtml (revision 7) @@ -0,0 +1,10 @@ +Project: memory_sizer

+Overview | +People | +Documentation | +Download | +OpenCores Mail list | +Contact me
+

+The People

+John E. Clayton from Scottsdale, Arizona, USA

Index: risc16f84/trunk/b13c_environment.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: risc16f84/trunk/b13c_environment.zip =================================================================== --- risc16f84/trunk/b13c_environment.zip (nonexistent) +++ risc16f84/trunk/b13c_environment.zip (revision 7)
risc16f84/trunk/b13c_environment.zip Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: risc16f84/trunk/download.shtml =================================================================== --- risc16f84/trunk/download.shtml (nonexistent) +++ risc16f84/trunk/download.shtml (revision 7) @@ -0,0 +1,24 @@ +Project: risc16f84

+Overview | +People | +Documentation | +Download | +OpenCores Mail list | +Contact me
+

Download

+

Allright, here are "the goods!"

+ +

Downloads:

+

+

risc16f84_clk2x.v. This file contains the stripped down 16f84 microcontroller: 1 interrupt input, no watch dog timer, no port A and B, plus the Auxiliary bus (which handles much more than Ports A and B), plus it runs at 2 clock cycles per instruction. +

risc16f84_small.v. This file contains the 16f84 Verilog code without EEPROM interface, with only a single interrupt input. +

risc16f84_lite.v. This file contains the 16f84 Verilog code without EEPROM interface. +

risc16f84.v. This file contains the full-blown 16f84 Verilog code. +

+

+b11_risc16f84_05_07_02.zip. +This file contains an example of the risc16f84_clk2x module in use. The top level module is "top.v" It uses tri-state buffers for data buses, except for the Xilinx DPRAM used to implement the 512 byte register file, which has separate data in and data out buses. There is support for hardware breakpoints, single stepping and resetting the processor through "rs232_syscon" commands given through a serial port (see opencores project at rs232_syscon).

+

This entire project fits into a Xilinx XC2S200 chip, taking up only about 950 slices or so, and all 14 of the DPRAM blocks (9 of the DPRAMS for a "pixel" memory for a 128 by 96 pixel display that I implemented with this project. You can remove these from the project, add new registers, create new peripherals -- whatever you like.) +

NOTE: In order to get these examples to work on your own board, you will need to generate a correct BAUD clock on your board -- see the file "serial.v" for details. Also, you will need some "level translating" circuit to change the LVTTL level signals coming out of the Xilinx chip into RS232 levels for connection to your computer's serial port. Be sure to re-assign the IO constraints to match the desired pinouts on your board, and add debug outputs if you like, so that you can view what is happening on a logic analyzer... Or, you could also simulate these modules! +

+ Index: risc16f84/trunk/index.shtml =================================================================== --- risc16f84/trunk/index.shtml (nonexistent) +++ risc16f84/trunk/index.shtml (revision 7) @@ -0,0 +1,7 @@ +Project: risc16f84

+People | +Documentation | +Download | +OpenCores Mail list | +Contact me

Description

The risc16f84 project is intended to provide a small, easy to use microcontroller in Verilog. The original code was VHDL, but I have done a wonderful translation of it into good clean Verilog code. (Well, I think it is wonderful, anyway.) The VHDL code was called "CQPIC" and it was published in 1999 by Sumio Morioka of Japan, in the December 1999 issue of "Transistor Gijutsu Magazine." I did the translation by hand, and then tested the design in actual hardware by running C code on it, and looking for correct behavior. I realize that this is not 100% test coverage, but I have found and fixed several bugs by this method -- including an error in the carry bit logic of the original code! There are four separate versions of the microcontroller presented here. The "original" one is called "risc16f84.v" and it includes all the logic needed to implement the entire 16f84 chip functionality as published in the original article.

However, I have realized over time, that a person using a microcontroller inside of an FPGA does not have the same constraints (i.e. on port sizes, number of pins, multiple functions needed on each pin, etc.) as the original chip designers, and so I have taken liberty in the other three versions, to simplify the logic by removing items that may not be wanted inside of an FPGA or ASIC implementation. For example, there is a version called "risc16f84_lite.v" which has no interface for the EEPROM...

Another version, called "risc16f84_small.v" further eliminates the multiple interrupt sources present on the original chip (since in a PIC there is only one interrupt vector defined, so interrupt service routines must do some "checking" anyway to determine the source of an interrupt - why bother having separate inputs defined? Just make up your own interrupt structure and use it the way you like inside of your chip!)

Finally, the fourth version, called "risc16f84_clk2x.v" further removes the port A and port B interfaces, since you can create as many ports as you like inside of your own chip. Toward this end, "risc16f84_clk2x.v" also includes an "auxiliary" bus interface, allowing the microcontroller to access 64k bytes of registers, ports and hardware peripherals, all defined within their own address space -- not within the limited register space of the PIC microcontrollers. I have used it to address a screen with 12288 pixels, and each pixel has its own address. It is easy to define addresses for the auxiliary bus components in most PIC code generation tools, so this works out nicely.

The code is written in Verilog, and was sythesized into a Xilinx SpartanII XC2S200 chip. Debugging was done in actual hardware, with an HP16500 series logic analyzer, and there are no simulation testbenches for these modules.

+

The design team welcomes any kind of help and feedback on these cores. If you are interested in further development of this project, please contact us.


Current Status:

  • The "risc16f84_clk2x.v" core has been coded completely, synthesized and tested for correct operation (and debugged!) inside a Xilinx XC2S200 chip. The tools used for development were the Xilinx Foundation 3.1i (non-ISE) tools.
  • The original "risc16f84.v" supports execution with 4 clocks per instruction, as in PIC microcontrollers.
  • The "risc16f84_clk2x" version uses only 2 clocks per instruction.
  • The "risc16f84_clk2x.v" core was tested at 49.125 MHz (approx. 25 MIPS), and uses 321 Virtex slices.
  • Xilinx DPRAM blocks were used to implement the processor register space and program ROM. These RAMs are dual-ported, so I have mapped the other port into the "auxiliary bus" space.
  • Debugging is aided by the use of "rs232_syscon.v" which is a hardware "monitor" that allows read/write of addresses on the auxiliary bus.
  • Since the registers and all useful peripherals are present on the auxiliary bus, single stepping and hardware breakpoints are implemented through the rs232_syscon interface (a serial port connects to a terminal window.)
  • I have been downloading C code through the serial port, in the form of rs232_syscon write commands.
  • A PERL script transforms s-record files into rs232_syscon write commands.
  • The cores are parameterized.
  • The code has good comments.

Maintainer(s):

Mailing-list:

\ No newline at end of file Index: risc16f84/trunk =================================================================== --- risc16f84/trunk (nonexistent) +++ risc16f84/trunk (revision 7)
risc16f84/trunk Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: risc16f84/web_uploads =================================================================== --- risc16f84/web_uploads (nonexistent) +++ risc16f84/web_uploads (revision 7)
risc16f84/web_uploads Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: risc16f84/branches =================================================================== --- risc16f84/branches (nonexistent) +++ risc16f84/branches (revision 7)
risc16f84/branches Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: risc16f84/tags/V001/documentation.shtml =================================================================== --- risc16f84/tags/V001/documentation.shtml (nonexistent) +++ risc16f84/tags/V001/documentation.shtml (revision 7) @@ -0,0 +1,17 @@ +Project: risc16f84

+Overview | +People | +Documentation | +Download | +Opencores Mail list | +Contact me
+

Documentation

+The data sheet for a 16F84A microcontroller from Microchip contains a superset of all of the instruction formats supported in "risc16f84_clk2x.v" For example, the "CLRWDT" instruction is not supported in "risc16f84_clk2x.v" because there is no watch dog timer. Also, ports A and B do not exist in "risc16f84_clk2x.v" so the user should be aware that this is NOT a fully compatible PIC type microcontroller. Much of the existing PIC code WILL NOT RUN on this microcontroller design because of these incompatibilities, and many libraries of code provided with PIC compilers will depend upon features that are not supported in this module. +However, new code which is written specifically for the "risc16f84_clk2x.v" design will run just fine. +

+

Interrupts have not been tested at this time.

+

In order to get up and running with this module, please examine the example code which shows how the module was used during testing. Also, the code is full of good comments, and there is a fairly detailed explanation of the working of the module in the file header.

+

+ + + Index: risc16f84/tags/V001/risc16f84_clk2x.v =================================================================== --- risc16f84/tags/V001/risc16f84_clk2x.v (nonexistent) +++ risc16f84/tags/V001/risc16f84_clk2x.v (revision 7) @@ -0,0 +1,940 @@ +//--------------------------------------------------------------------------- +// RISC 16F84 "clk2x" core +// +// This file is part of the "risc_16F84" project. +// http://www.opencores.org/cores/risc_16F84 +// +// +// Description: See description below (which suffices for IP core +// specification document.) +// +// Copyright (C) 1999 Sumio Morioka (original VHDL design version) +// Copyright (C) 2001 John Clayton and OPENCORES.ORG (this Verilog version) +// +// NOTE: This source code is free for educational/hobby use only. It cannot +// be used for commercial purposes without the consent of Microchip +// Technology incorporated. +// +// This source file may be used and distributed without restriction provided +// that this copyright statement is not removed from the file and that any +// derivative work contains the original copyright notice and the associated +// disclaimer. +// +// This source file is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This source is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this source. +// If not, download it from http://www.opencores.org/lgpl.shtml +// +//--------------------------------------------------------------------------- +// +// Author: John Clayton +// Date : January 29, 2002 +// +// (NOTE: Date formatted as day/month/year.) +// Update: 29/01/02 copied this file from memory_sizer.v (pared down). +// Translated the module and signal declarations. +// Transformed the instruction wires to lowercase. +// Transformed the addressing wires to lowercase. +// Update: 31/01/02 Translated the instruction decoder. +// Update: 5/02/02 Determined that stack is simply a circular buffer of +// 8 locations, 13 bits per location. Started translating +// "main_efsm" process. Added all code from piccore.vhd +// into this file for eventual translation. Concluded that +// "stack_full_node" is not needed. +// Update: 6/02/02 Translated the "ram_i_node" if/else precedural assignment. +// Update: 7/02/02 Changed all := to <=, changed all '0' to 0 and '1' to 1. +// Replaced all " downto " with ":". +// Finished translating QRESET state. +// Update: 20/02/02 Replaced all instances of Qreset with QRESET_PP. Also +// replaced other state designations with their new names. +// Finished translating Q1, Q2 states. +// Update: 22/02/02 Translated section 2-4-1-1 (aluout register) +// Update: 27/02/02 Replaced all "or" with "||" in if statements +// Replaced all "and" with "&&" in if statements. +// Replaced all "not" with "~" in if statements. +// Finished translating Q3,Q4 states. +// Translated output signal assignments at end of code. +// Translated interrupt trigger processes. +// Update: 28/02/02 Finished translation of WDT and TMR0 prescaler. +// Trimmed line length to 80 characters throughout. +// Prepared to attempt initial syntax checking. +// Cleaned up some naming conventions, and verified that +// all I/O pins have _i or _o appended in the body of the +// code. +// Update: 03/04/02 Changed "progdata_i" to "prog_dat_i" Also changed +// "progadr_o" to "prog_adr_o" +// Update: 04/04/02 Created new file "risc16f84_lite.v" This file is reduced +// and simplified from the original "risc16f84.v" file. +// Specifically, I am removing EEPROM support, and +// consolidating porta and portb I/O pins so that they +// are bidirectional. +// Update: 04/04/02 Created a new file "risc16f84_small.v" This file is +// further reduced and simplified from "risc16f84_lite.v" +// Specifically, I am removing the prescaler, TMR0 and WDT. +// Also, I am removing support for portb interrupts, leaving +// only rb0/int as an interrupt source. This pin will be +// the only way to wake up from the SLEEP instruction... +// Obviously, the CLEARWDT instruction will no longer do +// anything. +// Update: 05/04/02 Removed the "powerdown_o", "startclk_o" and "clk_o" pins +// from the small design. Also removed "rbpu_o", so if you +// want pullups, you have to add them explicitly in the +// constraints file, and option_reg[7] doesn't control them. +// Update: 08/04/02 Decided to modify "risc16f84_small.v" in order to try for +// more performance (only 2 states per instruction!) +// The new file is called "risc16f84_clk2x.v" The resulting +// code was synthesized, but not tested yet. +// Update: 11/04/02 Decided to remove porta and portb from this unit, and add +// instead an auxiliary bus, which is intended to allow I/O +// using an indirect approach, similar to using the FSR. +// However, the aux_adr_o is 16 bits wide, so that larger +// RAM may be accessed indirectly by the processor... The use +// of FSR for this purpose proved undesirable, since any new +// page of RAM contains "holes" to accomodate the registers +// in the first 12 locations (including FSR!) so that large +// contiguous blocks of memory could not be accessed in an +// effective way. This auxiliary bus solves that problem. +// Since this processor is implemented inside of an FPGA, +// and it is not a goal to maintain compatibility with +// existing libraries of code, there is no need to maintain +// porta and portb in the hardware. +// The aux_adr_lo and aux_adr_hi registers are located at +// 88h and 89h, and the aux_dat_io location is decoded at +// 08h. +// Also, changed to using "ram_we_o" instead of "readram_o" +// and "writeram_o" +// Update: 16/04/02 Added clock enable signal, for processor single stepping. +// "aux_dat_io" is only driven when "clk_en_i" is high... +// Update: 17/04/02 Removed "reset_condition" and moved "inc_pc_node" out of +// the clocking area, making it non-registered. In fact, I +// moved everything other than the state machine out of the +// clocked logic section. Changed "aluout_reg" to "aluout" +// since it is no longer registered. +// Update: 26/04/02 Fixed bug in aluout logic. The AND and OR functions were +// coded with logical AND/OR instead of bitwise AND/OR! +// Update: 26/04/02 Changed location of aux_adr_lo and aux_adr_hi registers +// to 05h and 06h, respectively. This was done to save +// code space because when using the aux data bus, no bank +// switching is necessary since they will now reside in the +// same bank. +// Update: 01/05/02 Fixed another bug -- the rrf and rlf instructions were +// coded incorrectly. +// Update: 03/05/02 Fixed another bug -- the carry bit was incorrect (the +// problem was discovered while performing SUBWF X,W where +// W contained 0 and X contained 1. (1-0). The logic for +// the carry bit appears to have been incorrect even in +// the original VHDL code by Sumio Morioka. +// Update: 11/18/02 Fixed bug in PCL addressing mode (near line 791) +// Removed parameters associated with WDT. +// Update: 11/25/02 Re-wrote much of the main FSM. Attempted to generate logic +// to recognize the falling edge of an interrupt, and was +// unsuccessful (not simulation, actual hardware tests.) +// Realized that falling edge interrupt can be equivalent to +// rising edge interrupt with a NOT gate on the signal. Since +// NOTs are practically free inside of an FPGA, decided to +// abandon the negative edge aspect of recognizing interrupts. +// Therefore, removed the "option_reg" since it is no longer +// needed in this design. +// Update: 08/08/03 Fixed a mathematical error, which was introduced by the bug +// fix of 03/05/02. The fix of 03/05/02 correctly generated the +// C bit for subtraction of zero, but unfortunately it introduced +// an error such that all subtraction results were off by 1. +// Obviously, this was unacceptable, and I think it has been fixed +// by the new signals "c_subtract_zero" and "c_dig_subtract_zero" +// +// Description +//--------------------------------------------------------------------------- +// This logic module implements a small RISC microcontroller, with functions +// and instruction set very similar to those of the Microchip 16F84 chip. +// This work is a translation (from VHDL to Verilog) of the "CQPIC" design +// published in 1999 by Sumio Morioka of Japan, and published in the December +// 1999 issue of "Transistor Gijutsu Magazine." The translation was performed +// by John Clayton, without the use of any translation tools. +// +// Original version used as basis for translation: CQPIC version 1.00b +// (December 10, 2000) +// +// Further revisions and re-writing have been completed on this code by John +// Clayton. The interrupt mechanism has been completely re-done, and the +// way in which the program counter is generated is expressed in a new way. +// +// In the comments, a "cycle" is defined as a processor cycle of 2 states. +// Thus, passing through states Q2_PP and Q4_PP completes one cycle. +// The numbers "1-3" and so forth are left from the comments in the original +// source code used as the basis of the translation. +//--------------------------------------------------------------------------- + +`define STATEBIT_SIZE 2 // Size of state machine register (bits) + + +module risc16f84_clk2x ( + prog_dat_i, // [13:0] ROM read data + prog_adr_o, // [12:0] ROM address + ram_dat_i, // [7:0] RAM read data + ram_dat_o, // [7:0] RAM write data + ram_adr_o, // [8:0] RAM address; ram_adr[8:7] indicates RAM-BANK + ram_we_o, // RAM write strobe (H active) + aux_adr_o, // [15:0] Auxiliary address bus + aux_dat_io, // [7:0] Auxiliary data bus (tri-state bidirectional) + aux_we_o, // Auxiliary write strobe (H active) + int0_i, // PORT-B(0) INT + reset_i, // Power-on reset (H active) + clk_en_i, // Clock enable for all clocked logic + clk_i // Clock input +); + + +// You can change the following parameters as you would like +parameter STACK_SIZE_PP = 8; // Size of PC stack +parameter LOG2_STACK_SIZE_PP = 3; // Log_2(stack_size) + +// State definitions for state machine, provided as parameters to allow +// for redefinition of state values by the instantiator if desired. +parameter Q2_PP = 2'b00; // state Q2 +parameter Q4_PP = 2'b01; // state Q4 +parameter QINT_PP = 2'b10; // interrupt state (substitute for Q4) +parameter QSLEEP_PP = 2'b11; // sleep state + + +// I/O declarations + + // program ROM data bus/address bus +input [13:0] prog_dat_i; // ROM read data +output [12:0] prog_adr_o; // ROM address + + // data RAM data bus/address bus/control signals +input [7:0] ram_dat_i; // RAM read data +output [7:0] ram_dat_o; // RAM write data +output [8:0] ram_adr_o; // RAM address; ram_adr[8:7] indicates RAM-BANK +output ram_we_o; // RAM write strobe (H active) + + // auxiliary data bus/address bus/control signals +output [15:0] aux_adr_o; // AUX address bus +inout [7:0] aux_dat_io; // AUX data bus +output aux_we_o; // AUX write strobe (H active) + + // interrupt input +input int0_i; // INT + + // CPU reset +input reset_i; // Power-on reset (H active) + + // CPU clock +input clk_en_i; // Clock enable input +input clk_i; // Clock input + + +// Internal signal declarations + + // User registers +reg [7:0] w_reg; // W +reg [12:0] pc_reg; // PCH/PCL -- Address currently being fetched +reg [12:0] old_pc_reg; // Address fetched previous to this one. +reg [7:0] status_reg; // STATUS +reg [7:0] fsr_reg; // FSR +reg [4:0] pclath_reg; // PCLATH +reg [7:0] intcon_reg; // INTCON +reg [7:0] aux_adr_hi_reg; // AUX address high byte +reg [7:0] aux_adr_lo_reg; // AUX address low byte + + // Internal registers for controlling instruction execution +reg [13:0] inst_reg; // Holds fetched op-code/operand +reg [7:0] aluinp1_reg; // data source (1 of 2) +reg [7:0] aluinp2_reg; // data source (2 of 2) +reg exec_stall_reg; // if H (i.e. after GOTO etc), stall execution. + + // Stack + // stack (array of data-registers) +reg [12:0] stack_reg [STACK_SIZE_PP-1:0]; + // stack pointer +reg [LOG2_STACK_SIZE_PP-1:0] stack_pnt_reg; +wire [12:0] stack_top; // More compatible with sensitivity list than + // "stack_reg[stack_pnt_reg]" + + // Interrupt registers/nodes +wire int_condition; // Indicates that an interrupt should be recognized +wire intrise; // High indicates edge was detected +reg intrise_reg; // detect positive edge of PORT-B inputs + // Synchronizer for interrupt +reg inte_sync_reg; + + // State register +reg [`STATEBIT_SIZE-1:0] state_reg; +reg [`STATEBIT_SIZE-1:0] next_state_node; + + // Result of decoding instruction -- only 1 is active at a time +wire inst_addlw; +wire inst_addwf; +wire inst_andlw; +wire inst_andwf; +wire inst_bcf; +wire inst_bsf; +wire inst_btfsc; +wire inst_btfss; +wire inst_call; +wire inst_clrf; +wire inst_clrw; +wire inst_comf; +wire inst_decf; +wire inst_decfsz; +wire inst_goto; +wire inst_incf; +wire inst_incfsz; +wire inst_iorlw; +wire inst_iorwf; +wire inst_movlw; +wire inst_movf; +wire inst_movwf; +wire inst_retfie; +wire inst_retlw; +wire inst_ret; +wire inst_rlf; +wire inst_rrf; +wire inst_sleep; +wire inst_sublw; +wire inst_subwf; +wire inst_swapf; +wire inst_xorlw; +wire inst_xorwf; + + // Result of calculating RAM access address +wire [8:0] ram_adr_node; // RAM access address + + // These wires indicate accesses to special registers... + // Only 1 is active at a time. +wire addr_pcl; +wire addr_stat; +wire addr_fsr; +wire addr_pclath; +wire addr_intcon; +wire addr_aux_adr_lo; +wire addr_aux_adr_hi; +wire addr_aux_dat; +wire addr_sram; + + // Other output registers (for removing hazards) +reg ram_we_reg; // data-sram write strobe +reg aux_we_reg; // AUX write strobe + + + // Signals used in "main_efsm" procedure + // (Intermediate nodes used for resource sharing.) +wire [7:0] ram_i_node; // result of reading RAM/Special registers +wire [7:0] mask_node; // bit mask for logical operations +wire [8:0] add_node; // result of 8bit addition +wire [4:0] addlow_node; // result of low-4bit addition +wire aluout_zero_node; // H if ALUOUT = 0 + +reg [12:0] next_pc_node; // value of next PC +reg [7:0] aluout; // result of calculation +reg writew_node; // H if destination is W register +reg writeram_node; // H if destination is RAM/Special registers +reg c_subtract_zero; // High for special case of C bit, when subtracting zero +reg c_dig_subtract_zero; // High for special case of C bit, when subtracting zero + +wire next_exec_stall; + +//-------------------------------------------------------------------------- +// Instantiations +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- +// Functions & Tasks +//-------------------------------------------------------------------------- + +//-------------------------------------------------------------------------- +// Module code +//-------------------------------------------------------------------------- + +// This represents the instruction fetch from program memory. +// inst_reg[13:0] stores the instruction. This happens at the end of Q4. +// So the memory access time is one processor cycle (2 clocks!) minus +// the setup-time of this register, and minus the delay to drive the +// address out onto the prog_adr_o bus. +always @(posedge clk_i) +begin + if (reset_i) inst_reg <= 0; + else if (clk_en_i && (state_reg == Q4_PP)) inst_reg <= prog_dat_i; +end + +// NOTE: There is an extra "15th" bit of inst_reg, which represents an +// interrupt execution cycle. This is included in inst_reg so that when +// an interrupt instruction is executing, it effectively "pre-empts" the +// other instructions. +// The fifteenth bit, inst_reg[14], is set by the interrupt logic. + +// Decode OPcode (see pp.54 of PIC16F84 data sheet) +// only 1 signal of the following signals will be '1' +assign inst_call = (inst_reg[13:11] == 3'b100 ); +assign inst_goto = (inst_reg[13:11] == 3'b101 ); +assign inst_bcf = (inst_reg[13:10] == 4'b0100 ); +assign inst_bsf = (inst_reg[13:10] == 4'b0101 ); +assign inst_btfsc = (inst_reg[13:10] == 4'b0110 ); +assign inst_btfss = (inst_reg[13:10] == 4'b0111 ); +assign inst_movlw = (inst_reg[13:10] == 4'b1100 ); +assign inst_retlw = (inst_reg[13:10] == 4'b1101 ); +assign inst_sublw = (inst_reg[13:9] == 5'b11110 ); +assign inst_addlw = (inst_reg[13:9] == 5'b11111 ); +assign inst_iorlw = (inst_reg[13:8] == 6'b111000 ); +assign inst_andlw = (inst_reg[13:8] == 6'b111001 ); +assign inst_xorlw = (inst_reg[13:8] == 6'b111010 ); +assign inst_subwf = (inst_reg[13:8] == 6'b000010 ); +assign inst_decf = (inst_reg[13:8] == 6'b000011 ); +assign inst_iorwf = (inst_reg[13:8] == 6'b000100 ); +assign inst_andwf = (inst_reg[13:8] == 6'b000101 ); +assign inst_xorwf = (inst_reg[13:8] == 6'b000110 ); +assign inst_addwf = (inst_reg[13:8] == 6'b000111 ); +assign inst_movf = (inst_reg[13:8] == 6'b001000 ); +assign inst_comf = (inst_reg[13:8] == 6'b001001 ); +assign inst_incf = (inst_reg[13:8] == 6'b001010 ); +assign inst_decfsz = (inst_reg[13:8] == 6'b001011 ); +assign inst_rrf = (inst_reg[13:8] == 6'b001100 ); +assign inst_rlf = (inst_reg[13:8] == 6'b001101 ); +assign inst_swapf = (inst_reg[13:8] == 6'b001110 ); +assign inst_incfsz = (inst_reg[13:8] == 6'b001111 ); +assign inst_movwf = (inst_reg[13:7] == 7'b0000001 ); +assign inst_clrw = (inst_reg[13:7] == 7'b0000010 ); +assign inst_clrf = (inst_reg[13:7] == 7'b0000011 ); +assign inst_ret = (inst_reg[13:0] == 14'b00000000001000); +assign inst_retfie = (inst_reg[13:0] == 14'b00000000001001); +assign inst_sleep = (inst_reg[13:0] == 14'b00000001100011); + + +// Calculate RAM access address (see pp.19 of PIC16F84 data sheet) + + // if "d"=0, indirect addressing is used, so RAM address is BANK+FSR + // otherwise, RAM address is BANK+"d" + // (see pp.19 of PIC16F84 data sheet) +assign ram_adr_node = (inst_reg[6:0]==0)?{status_reg[7],fsr_reg[7:0]}: + {status_reg[6:5],inst_reg[6:0]}; + + // check if this is an access to external RAM or not +assign addr_sram = (ram_adr_node[6:0] > 7'b0001011); //0CH-7FH,8CH-FFH + + // check if this is an access to special register or not + // only 1 signal of the following signals will be '1' +assign addr_pcl = (ram_adr_node[6:0] == 7'b0000010); // 02H, 82H +assign addr_stat = (ram_adr_node[6:0] == 7'b0000011); // 03H, 83H +assign addr_fsr = (ram_adr_node[6:0] == 7'b0000100); // 04H, 84H +assign addr_aux_dat = (ram_adr_node[7:0] == 8'b00001000); // 08H +assign addr_pclath = (ram_adr_node[6:0] == 7'b0001010); // 0AH, 8AH +assign addr_intcon = (ram_adr_node[6:0] == 7'b0001011); // 0BH, 8BH +assign addr_aux_adr_lo = (ram_adr_node[7:0] == 8'b00000101); // 05H +assign addr_aux_adr_hi = (ram_adr_node[7:0] == 8'b00000110); // 06H + +// construct bit-mask for logical operations and bit tests +assign mask_node = 1 << inst_reg[9:7]; + +// Create the exec_stall signal, based on the contents of the currently +// executing instruction (inst_reg). next_exec_stall reflects the state +// to assign to exec_stall following the conclusion of the next Q4 state. +// All of these instructions cause an execution stall in the next cycle +// because they modify the program counter, and a new value is presented +// for fetching during the stall cycle, during which time no instruction +// should be executed. +// +// The conditional instructions are given along with their conditions for +// execution. If the conditions are not met, there is no stall and nothing +// to execute. +assign next_exec_stall = ( + inst_goto + || inst_call + || inst_ret + || inst_retlw + || inst_retfie + || ( + (inst_btfsc || inst_decfsz || inst_incfsz) + && aluout_zero_node + ) + || (inst_btfss && ~aluout_zero_node) + || (addr_pcl && writeram_node) + ); +always @(posedge clk_i) +begin + if (reset_i) exec_stall_reg <= 0; + else if (clk_en_i && (state_reg == QINT_PP)) exec_stall_reg <= 1; + else if (clk_en_i && (state_reg == Q4_PP)) + exec_stall_reg <= (next_exec_stall && ~exec_stall_reg); + // exec stall should never be generated during a stall cycle, because + // a stall cycle doesn't execute anything... +end + +assign stack_top = stack_reg[stack_pnt_reg]; +// Formulate the next pc_reg value (the program counter.) +// During stall cycles, the pc is simply incremented... +always @( + pc_reg + or pclath_reg + or aluout + or stack_pnt_reg + or stack_top + or inst_ret + or inst_retlw + or inst_retfie + or inst_goto + or inst_call + or inst_reg + or writeram_node + or addr_pcl + or exec_stall_reg + ) +begin + if (~exec_stall_reg &&(inst_ret || inst_retlw || inst_retfie)) + next_pc_node <= stack_top; + else if (~exec_stall_reg &&(inst_goto || inst_call)) + next_pc_node <= {pclath_reg[4:3],inst_reg[10:0]}; + else if (~exec_stall_reg && (writeram_node && addr_pcl)) + // PCL is data-destination, but update the entire PC. + next_pc_node <= {pclath_reg[4:0],aluout}; + else + next_pc_node <= pc_reg + 1; +end + +// Set the program counter +// If the sleep instruction is executing, then the PC is not allowed to be +// updated, since the processor will "freeze" and the instruction being fetched +// during the sleep instruction must be executed upon wakeup interrupt. +// Obviously, if the PC were to change at the end of the sleep instruction, then +// a different (incorrect) address would be fetched during the sleep time. +always @(posedge clk_i) +begin + if (reset_i) begin + pc_reg <= 0; + old_pc_reg <= 0; + end + else if (clk_en_i && (state_reg == QINT_PP)) + begin + old_pc_reg <= pc_reg; + pc_reg <= 4; + end + else if (clk_en_i && ~inst_sleep && (state_reg == Q4_PP)) + begin + old_pc_reg <= pc_reg; + pc_reg <= next_pc_node; + end +end + +// 1. Intermediate nodes for resource sharing + +// Tri-state drivers instead of a huge selector... It produces smaller +// results, and runs faster. +assign ram_i_node = (addr_sram) ?ram_dat_i:8'bZ; +assign ram_i_node = (addr_pcl) ?pc_reg[7:0]:8'bZ; +assign ram_i_node = (addr_stat) ?status_reg:8'bZ; +assign ram_i_node = (addr_fsr) ?fsr_reg:8'bZ; +assign ram_i_node = (addr_aux_dat) ?aux_dat_io:8'bZ; +assign ram_i_node = (addr_pclath) ?{3'b0,pclath_reg}:8'bZ; +assign ram_i_node = (addr_intcon) ?intcon_reg:8'bZ; +assign ram_i_node = (addr_aux_adr_lo) ?aux_adr_lo_reg:8'bZ; +assign ram_i_node = (addr_aux_adr_hi) ?aux_adr_hi_reg:8'bZ; + +// 1-3. Adder (ALU) +// full 8bit-addition, with carry in/out. +// Note that "temp" and "dtemp" are intended to be thrown away. +// Also, addlow_node[3:0] are thrown away. +// Even though they are assigned, they should never be used. +assign add_node = {1'b0,aluinp1_reg} + + {1'b0,aluinp2_reg}; +// lower 4bit-addition +assign addlow_node = {1'b0,aluinp1_reg[3:0]} + + {1'b0,aluinp2_reg[3:0]}; + +// 1-4. Test if aluout = 0 +assign aluout_zero_node = (aluout == 0)?1:0; + +// 1-5. Determine destination +always @( + inst_reg + or inst_movwf + or inst_bcf + or inst_bsf + or inst_clrf + or inst_movlw + or inst_addlw + or inst_sublw + or inst_andlw + or inst_iorlw + or inst_xorlw + or inst_retlw + or inst_clrw + or inst_movf + or inst_swapf + or inst_addwf + or inst_subwf + or inst_andwf + or inst_iorwf + or inst_xorwf + or inst_decf + or inst_incf + or inst_rlf + or inst_rrf + or inst_decfsz + or inst_incfsz + or inst_comf + ) +begin + if (inst_movwf || inst_bcf || inst_bsf || inst_clrf) + begin + writew_node <= 0; + writeram_node <= 1; + end + else if ( inst_movlw || inst_addlw || inst_sublw || inst_andlw + || inst_iorlw || inst_xorlw || inst_retlw || inst_clrw) + begin + writew_node <= 1; + writeram_node <= 0; + end + else if ( inst_movf || inst_swapf || inst_addwf || inst_subwf + || inst_andwf || inst_iorwf || inst_xorwf || inst_decf + || inst_incf || inst_rlf || inst_rrf || inst_decfsz + || inst_incfsz || inst_comf) + begin + writew_node <= ~inst_reg[7]; // ("d" field of fetched instruction) + writeram_node <= inst_reg[7]; // ("d" field of fetched instruction) + end + else + begin + writew_node <= 0; + writeram_node <= 0; + end +end // End of determine destination logic + + + + +// 2-4-1. Calculation and store result into alu-output register + +always @( + add_node + or aluinp1_reg + or aluinp2_reg + or status_reg + or inst_reg + or inst_movwf + or inst_bcf + or inst_bsf + or inst_btfsc + or inst_btfss + or inst_clrf + or inst_addlw + or inst_sublw + or inst_andlw + or inst_iorlw + or inst_xorlw + or inst_retlw + or inst_clrw + or inst_swapf + or inst_addwf + or inst_subwf + or inst_andwf + or inst_iorwf + or inst_xorwf + or inst_decf + or inst_incf + or inst_rlf + or inst_rrf + or inst_decfsz + or inst_incfsz + or inst_comf + ) +begin + // 2-4-1-1. Set aluout register + // Rotate left + if (inst_rlf) + aluout <= {aluinp1_reg[6:0],status_reg[0]}; + // Rotate right + else if (inst_rrf) + aluout <= {status_reg[0],aluinp1_reg[7:1]}; + // Swap nibbles + else if (inst_swapf) + aluout <= {aluinp1_reg[3:0],aluinp1_reg[7:4]}; + // Logical inversion + else if (inst_comf) + aluout <= ~aluinp1_reg; + // Logical AND, bit clear/bit test + else if ( inst_andlw || inst_andwf || inst_bcf || inst_btfsc + || inst_btfss) + aluout <= (aluinp1_reg & aluinp2_reg); + // Logical OR, bit set + else if (inst_bsf || inst_iorlw || inst_iorwf) + aluout <= (aluinp1_reg | aluinp2_reg); + // Logical XOR + else if (inst_xorlw || inst_xorwf) + aluout <= (aluinp1_reg ^ aluinp2_reg); + // Addition, Subtraction, Increment, Decrement + else if ( inst_addlw || inst_addwf || inst_sublw || inst_subwf + || inst_decf || inst_decfsz || inst_incf || inst_incfsz) + aluout <= add_node[7:0]; + // Pass through + else aluout <= aluinp1_reg; +end + + +// MAIN EFSM: description of register value changes in each clock cycle +always @(posedge clk_i) +begin + // Assign reset (default) values of registers + if (reset_i) + begin + status_reg[7:5] <= 3'b0; + pclath_reg <= 0; // 0 + intcon_reg[7:1] <= 7'b0; + aux_adr_lo_reg <= 0; + aux_adr_hi_reg <= 0; + ram_we_reg <= 0; + status_reg[4] <= 1; // /T0 = 1 + status_reg[3] <= 1; // /PD = 1 + stack_pnt_reg <= 0; // Reset stack pointer + end // End of reset assignments + else if (~exec_stall_reg && clk_en_i) + begin // Execution ceases during a stall cycle. + if (state_reg == Q2_PP) // 2-3. Q2 cycle + begin + // 2-3-1. Read data-RAM and store values to alu-input regs + // 2-3-1-1. Set aluinp1 register (source #1) + if ( inst_movf || inst_swapf || inst_addwf || inst_subwf + || inst_andwf || inst_iorwf || inst_xorwf || inst_decf + || inst_incf || inst_rlf || inst_rrf || inst_bcf + || inst_bsf || inst_btfsc || inst_btfss || inst_decfsz + || inst_incfsz || inst_comf) + + aluinp1_reg <= ram_i_node; // RAM/Special registers + else + if ( inst_movlw || inst_addlw || inst_sublw || inst_andlw + || inst_iorlw || inst_xorlw || inst_retlw) + aluinp1_reg <= inst_reg[7:0]; // Immediate value ("k") + else + if ( inst_clrf || inst_clrw) aluinp1_reg <= 0; // 0 + else aluinp1_reg <= w_reg; // W register + + // 2-3-1-2. Set aluinp2 register (source #2) + c_subtract_zero <= 0; // default to non-special case + c_dig_subtract_zero <= 0; // default to non-special case + if (inst_decf || inst_decfsz) aluinp2_reg <= -1; // for decr. + else if (inst_incf || inst_incfsz) aluinp2_reg <= 1; // for incr. + // -1 * W register (for subtract) + else if (inst_sublw || inst_subwf) + begin + aluinp2_reg <= ~w_reg + 1; + c_subtract_zero <= (w_reg == 0); // Indicate special case + c_dig_subtract_zero <= (w_reg[3:0] == 0); // Indicate special case + end + // operation of BCF: AND with inverted mask ("1..101..1") + // mask for BCF: value of only one position is 0 + else if (inst_bcf) aluinp2_reg <= ~mask_node; + // operation of BSF: OR with mask_node ("0..010..0") + // operation of FSC and FSS: AND with mask_node, compare to 0 + else if (inst_btfsc || inst_btfss || inst_bsf) + aluinp2_reg <= mask_node; + else aluinp2_reg <= w_reg; // W register + + // 2-3-1-3. Set stack pointer register (pop stack) + if (inst_ret || inst_retlw || inst_retfie) + stack_pnt_reg <= stack_pnt_reg - 1; // cycles 3,2,1,0,7,6... + + // 2-4-1-3. Set data-SRAM write enable (hazard-free) + // Set the write enables depending on the destination. + // (These have been implemented as registers to avoid glitches? + // It is not known to me (John Clayton) whether any glitches would + // really occur. It might be possible to generate these signals + // using combinational logic only, without using registers! + ram_we_reg <= (writeram_node && addr_sram); + aux_we_reg <= (writeram_node && addr_aux_dat); + end // End of Q2 state + + //--------------------------------------------------------------------- + + else if (state_reg == QINT_PP) // Interrupt execution (instead of Q4_PP) + begin + // PORT-B0 INT + intcon_reg[1] <= 1; // set INTF + intcon_reg[7] <= 0; // clear GIE + stack_reg[stack_pnt_reg] <= old_pc_reg; // Push old PC + stack_pnt_reg <= stack_pnt_reg + 1; // increment stack pointer + // The old PC is pushed, so that the pre-empted instruction can be + // restarted later, when the retfie is executed. + end + + //--------------------------------------------------------------------- + + else if (state_reg == Q4_PP) // Execution & writing of results. + begin + + if (inst_call) + begin + stack_reg[stack_pnt_reg] <= pc_reg; // Push current PC + stack_pnt_reg <= stack_pnt_reg + 1; // increment stack pointer + end + + if (inst_retfie) // "return from interrupt" instruction + begin + intcon_reg[7] <= 1; // Set GIE + end + + // 2-4-1-2. Set C flag and DC flag + if (inst_addlw || inst_addwf || inst_sublw || inst_subwf) + begin + // c_dig_subtract_zero and c_subtract_zero are used to take care of the + // special case when subtracting zero, where the carry bit should be 1 + // (meaning no borrow). It is explicitly set by these signals during + // that condition. See 16F84 datasheet, page 8 for further information + // about the C bit. + status_reg[1] <= addlow_node[4] || c_dig_subtract_zero; // DC flag + status_reg[0] <= add_node[8] || c_subtract_zero; // C flag + end + else if (inst_rlf) status_reg[0] <= aluinp1_reg[7]; // C flag + else if (inst_rrf) status_reg[0] <= aluinp1_reg[0]; // C flag + + // 2-5-2. Store calculation result into destination, + // 2-5-2-1. Set W register + + if (writew_node) w_reg <= aluout; // write W reg + + // 2-5-2-2. Set data RAM/special registers, + if (writeram_node) + begin + if (addr_stat) + begin + status_reg[7:5] <= aluout[7:5]; // write IRP,RP1,RP0 + // status(4),status(3)...unwritable, see below (/PD,/T0 part) + status_reg[1:0] <= aluout[1:0]; // write DC,C + end + if (addr_fsr) fsr_reg <= aluout; // write FSR + if (addr_pclath) pclath_reg <= aluout[4:0]; // write PCLATH + if (addr_intcon) intcon_reg <= aluout; // write INTCON + if (addr_aux_adr_lo) aux_adr_lo_reg <= aluout; // write AUX low + if (addr_aux_adr_hi) aux_adr_hi_reg <= aluout; // write AUX high + end + + // 2-5-2-3. Set/clear Z flag. + if (addr_stat) status_reg[2] <= aluout[2]; // (dest. is Z flag) + else if ( inst_addlw || inst_addwf || inst_andlw || inst_andwf + || inst_clrf || inst_clrw || inst_comf || inst_decf + || inst_incf || inst_movf || inst_sublw || inst_subwf + || inst_xorlw || inst_xorwf || inst_iorlw || inst_iorwf ) + status_reg[2] <= aluout_zero_node; // Z=1 if result == 0 + + // 2-5-3. Clear RAM write enables (hazard-free) + ram_we_reg <= 0; + aux_we_reg <= 0; + + end // End of Q4 state + end // End of "if (~exec_stall_reg)" +end // End of process + + +// Calculation of next processor state. +// (Not including reset conditions, which are covered by the clocked logic, +// which also includes a "global clock enable." +always @( + state_reg + or inst_sleep + or inte_sync_reg + or exec_stall_reg + or int_condition + ) +begin + case (state_reg) + Q2_PP : if (int_condition) next_state_node <= QINT_PP; + else next_state_node <= Q4_PP; + Q4_PP : if (~exec_stall_reg && inst_sleep) next_state_node <= QSLEEP_PP; + else next_state_node <= Q2_PP; + QINT_PP : next_state_node <= Q2_PP; + QSLEEP_PP : if (inte_sync_reg) next_state_node <= Q2_PP; + else next_state_node <= QSLEEP_PP; + // Default condition provided for convention and completeness + // only. Logically, all of the conditions are already covered. + default : next_state_node <= Q2_PP; + endcase +end + + +// Clocked state transitions, based upon dataflow (non-clocked logic) in +// the previous always block. +always @(posedge clk_i) +begin + if (reset_i) state_reg <= Q2_PP; + else if (clk_en_i) state_reg <= next_state_node; +end // End of process + + +// Detect external interrupt requests +// You can code multiple interrupts if you wish, or use the single interrupt +// provided and simply have the interrupt service routine (ISR) check to find +// out the source of the interrupt, by or-ing together all of the interrupt +// sources and providing a readable register of their values at the time +// the interrupt occurred. +// +// When an interrupt is recognized by the processor, this is signified by +// entering "QINT_PP," which is treated like an executable instruction. +// The interrupt instruction can only be executed when not in a stall condition. +// It simply "pre-empts" the instruction that would have been executed during +// that cycle. Then, when retfie is executed, the pre-empted instruction is +// re-started (the stall cycle of the retfie is when the address of the +// instruction being re-started is fetched.) +// +// I was unable to obtain correct operation for capturing the negative edge, +// so I am discarding it. If one really needs to generate an interrupt on the +// falling edge, just use an inverted version of the signal (the inversion is +// often "free" inside of an FPGA anyhow.) +// +// Upon further testing, I discovered that even the rising edge "trigger" was not +// really truly an edge detection, it was more like a "set-reset" flip flop +// type of behavior. Rather than mess around with it any more, I am implementing +// a clocked "poor man's rising edge detector." +// Capture the rising edge of the interrupt input... This part is self clearing. +// It also means that the interrupt must last longer than one clock cycle in +// order to be properly recognized. (It is "pseudo edge triggered", not a true +// rising edge trigger.) +// When the interrupt is recognized, inte_sync_reg is cleared. + + +always @(posedge clk_i) +begin + if (clk_en_i) intrise_reg <= int0_i; +end // process +assign intrise = (int0_i && ~intrise_reg); + +// The inte_sync_reg signal is used for waking up from SLEEP. +// (this flip flop is also a synchronizer to minimize the +// possibility of metastability due to changes at the input +// occurring at the same time as the processor clock edge...) +// It might be possible to eliminate this step, and issue the interrupt +// directly without this intermediate synchronizer flip-flop. +always @(posedge clk_i) +begin + if (reset_i || (state_reg == QINT_PP)) inte_sync_reg <= 0; + else if (clk_en_i && intrise && intcon_reg[4]) inte_sync_reg <= 1; +end + +// Issue an interrupt when the interrupt is present. +// Also, do not issue an interrupt when there is a stall cycle coming! +assign int_condition = (inte_sync_reg && ~exec_stall_reg && intcon_reg[7]); + // Interrupt must be pending + // Next processor cycle must not be a stall + // GIE bit must be set to issue interrupt + +// Circuit's output signals +assign prog_adr_o = pc_reg; // program ROM address +assign ram_adr_o = ram_adr_node; // data RAM address +assign ram_dat_o = aluout; // data RAM write data +assign ram_we_o = ram_we_reg; // data RAM write enable + +assign aux_adr_o = {aux_adr_hi_reg,aux_adr_lo_reg}; +assign aux_dat_io = (aux_we_reg && clk_en_i)?aluout:{8{1'bZ}}; +assign aux_we_o = aux_we_reg; + +endmodule + + +//`undef STATEBIT_SIZE \ No newline at end of file Index: risc16f84/tags/V001/srec_to_rs232.pl =================================================================== --- risc16f84/tags/V001/srec_to_rs232.pl (nonexistent) +++ risc16f84/tags/V001/srec_to_rs232.pl (revision 7) @@ -0,0 +1,67 @@ +#!/usr/bin/perl -w +print "\nMotorola S-record to rs232_syscon command translator."; +print "\nFilename to translate? "; +$filename = ; +chomp ($filename); +print "\nReading file \"$filename\"\n"; +open (SRECORDFILE,$filename) || + die "\nCan't open \"$filename\" for input.\n"; + +# Handle getting a new extension for the output filename +$i = index($filename,"."); + # If no period is found, simply add the extension to the end. +if ($i < 0) { $i = length($filename); } +substr($filename,$i,4) = ".232"; + +# Open the output file +open (OUTPUTFILE,">".$filename) || + die "\nCan't open \"$filename\" for output.\n"; + +$line_number = 0; +while ($line = ) { + # increment the line number counter + $line_number += 1; + # ignore lines that begin with semicolon + if (index($line,";")==0) { next; } + # Get the position of the start of data + # (Usually there is a colon at the very start of the line...) + $i = index($line,":"); + if ($i < 0) { + print "\nError! No colon found on line: $line_number"; + last; + } + # Get the length of the line + $line_length = hex(substr($line,($i+1),2)); + if ($line_length == 0) { + print "0"; + next; + } + + # Extract the starting address + $line_starting_address = hex(substr($line,($i+3),4)); + + # Extract the data substring - length is in units of bytes, + # but each character is 1/2 byte, so multiply by 2. + $line_data = substr($line,($i+9),($line_length*2)); + + # Send data characters to output file as rs232_syscon commands + # increment by 2 in order to send 1 byte per command... + for ($i=0;$i<($line_length*2);$i+=2) { + $j = $line_starting_address + $i/2; + $j = sprintf "%lx",$j; # Convert address to hexadecimal + $byte = substr($line_data,$i,2); + print OUTPUTFILE "w $j $byte\n"; + } + +# Verbose debug information... +# print "\nline $line_number: starts at $line_starting_address "; +# print "length is $line_length "; +# print "data is $line_data "; + # Print a little period for each line processed... + # (to complement the 0 printed for zero length lines encountered.) + print "."; + } + +#Close all open files +close (SRECORDFILE); +close (OUTPUTFILE); Index: risc16f84/tags/V001/Image4.gif =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: risc16f84/tags/V001/Image4.gif =================================================================== --- risc16f84/tags/V001/Image4.gif (nonexistent) +++ risc16f84/tags/V001/Image4.gif (revision 7)
risc16f84/tags/V001/Image4.gif Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: risc16f84/tags/V001/people.shtml =================================================================== --- risc16f84/tags/V001/people.shtml (nonexistent) +++ risc16f84/tags/V001/people.shtml (revision 7) @@ -0,0 +1,10 @@ +Project: memory_sizer

+Overview | +People | +Documentation | +Download | +OpenCores Mail list | +Contact me
+

+The People

+John E. Clayton from Scottsdale, Arizona, USA

Index: risc16f84/tags/V001/b13c_environment.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: risc16f84/tags/V001/b13c_environment.zip =================================================================== --- risc16f84/tags/V001/b13c_environment.zip (nonexistent) +++ risc16f84/tags/V001/b13c_environment.zip (revision 7)
risc16f84/tags/V001/b13c_environment.zip Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: risc16f84/tags/V001/download.shtml =================================================================== --- risc16f84/tags/V001/download.shtml (nonexistent) +++ risc16f84/tags/V001/download.shtml (revision 7) @@ -0,0 +1,24 @@ +Project: risc16f84

+Overview | +People | +Documentation | +Download | +OpenCores Mail list | +Contact me
+

Download

+

Allright, here are "the goods!"

+ +

Downloads:

+

+

risc16f84_clk2x.v. This file contains the stripped down 16f84 microcontroller: 1 interrupt input, no watch dog timer, no port A and B, plus the Auxiliary bus (which handles much more than Ports A and B), plus it runs at 2 clock cycles per instruction. +

risc16f84_small.v. This file contains the 16f84 Verilog code without EEPROM interface, with only a single interrupt input. +

risc16f84_lite.v. This file contains the 16f84 Verilog code without EEPROM interface. +

risc16f84.v. This file contains the full-blown 16f84 Verilog code. +

+

+b11_risc16f84_05_07_02.zip. +This file contains an example of the risc16f84_clk2x module in use. The top level module is "top.v" It uses tri-state buffers for data buses, except for the Xilinx DPRAM used to implement the 512 byte register file, which has separate data in and data out buses. There is support for hardware breakpoints, single stepping and resetting the processor through "rs232_syscon" commands given through a serial port (see opencores project at rs232_syscon).

+

This entire project fits into a Xilinx XC2S200 chip, taking up only about 950 slices or so, and all 14 of the DPRAM blocks (9 of the DPRAMS for a "pixel" memory for a 128 by 96 pixel display that I implemented with this project. You can remove these from the project, add new registers, create new peripherals -- whatever you like.) +

NOTE: In order to get these examples to work on your own board, you will need to generate a correct BAUD clock on your board -- see the file "serial.v" for details. Also, you will need some "level translating" circuit to change the LVTTL level signals coming out of the Xilinx chip into RS232 levels for connection to your computer's serial port. Be sure to re-assign the IO constraints to match the desired pinouts on your board, and add debug outputs if you like, so that you can view what is happening on a logic analyzer... Or, you could also simulate these modules! +

+ Index: risc16f84/tags/V001/index.shtml =================================================================== --- risc16f84/tags/V001/index.shtml (nonexistent) +++ risc16f84/tags/V001/index.shtml (revision 7) @@ -0,0 +1,7 @@ +Project: risc16f84

+People | +Documentation | +Download | +OpenCores Mail list | +Contact me

Description

The risc16f84 project is intended to provide a small, easy to use microcontroller in Verilog. The original code was VHDL, but I have done a wonderful translation of it into good clean Verilog code. (Well, I think it is wonderful, anyway.) The VHDL code was called "CQPIC" and it was published in 1999 by Sumio Morioka of Japan, in the December 1999 issue of "Transistor Gijutsu Magazine." I did the translation by hand, and then tested the design in actual hardware by running C code on it, and looking for correct behavior. I realize that this is not 100% test coverage, but I have found and fixed several bugs by this method -- including an error in the carry bit logic of the original code! There are four separate versions of the microcontroller presented here. The "original" one is called "risc16f84.v" and it includes all the logic needed to implement the entire 16f84 chip functionality as published in the original article.

However, I have realized over time, that a person using a microcontroller inside of an FPGA does not have the same constraints (i.e. on port sizes, number of pins, multiple functions needed on each pin, etc.) as the original chip designers, and so I have taken liberty in the other three versions, to simplify the logic by removing items that may not be wanted inside of an FPGA or ASIC implementation. For example, there is a version called "risc16f84_lite.v" which has no interface for the EEPROM...

Another version, called "risc16f84_small.v" further eliminates the multiple interrupt sources present on the original chip (since in a PIC there is only one interrupt vector defined, so interrupt service routines must do some "checking" anyway to determine the source of an interrupt - why bother having separate inputs defined? Just make up your own interrupt structure and use it the way you like inside of your chip!)

Finally, the fourth version, called "risc16f84_clk2x.v" further removes the port A and port B interfaces, since you can create as many ports as you like inside of your own chip. Toward this end, "risc16f84_clk2x.v" also includes an "auxiliary" bus interface, allowing the microcontroller to access 64k bytes of registers, ports and hardware peripherals, all defined within their own address space -- not within the limited register space of the PIC microcontrollers. I have used it to address a screen with 12288 pixels, and each pixel has its own address. It is easy to define addresses for the auxiliary bus components in most PIC code generation tools, so this works out nicely.

The code is written in Verilog, and was sythesized into a Xilinx SpartanII XC2S200 chip. Debugging was done in actual hardware, with an HP16500 series logic analyzer, and there are no simulation testbenches for these modules.

+

The design team welcomes any kind of help and feedback on these cores. If you are interested in further development of this project, please contact us.


Current Status:

  • The "risc16f84_clk2x.v" core has been coded completely, synthesized and tested for correct operation (and debugged!) inside a Xilinx XC2S200 chip. The tools used for development were the Xilinx Foundation 3.1i (non-ISE) tools.
  • The original "risc16f84.v" supports execution with 4 clocks per instruction, as in PIC microcontrollers.
  • The "risc16f84_clk2x" version uses only 2 clocks per instruction.
  • The "risc16f84_clk2x.v" core was tested at 49.125 MHz (approx. 25 MIPS), and uses 321 Virtex slices.
  • Xilinx DPRAM blocks were used to implement the processor register space and program ROM. These RAMs are dual-ported, so I have mapped the other port into the "auxiliary bus" space.
  • Debugging is aided by the use of "rs232_syscon.v" which is a hardware "monitor" that allows read/write of addresses on the auxiliary bus.
  • Since the registers and all useful peripherals are present on the auxiliary bus, single stepping and hardware breakpoints are implemented through the rs232_syscon interface (a serial port connects to a terminal window.)
  • I have been downloading C code through the serial port, in the form of rs232_syscon write commands.
  • A PERL script transforms s-record files into rs232_syscon write commands.
  • The cores are parameterized.
  • The code has good comments.

Maintainer(s):

Mailing-list:

\ No newline at end of file Index: risc16f84/tags =================================================================== --- risc16f84/tags (nonexistent) +++ risc16f84/tags (revision 7)
risc16f84/tags Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ##

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.