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

Subversion Repositories risc16f84

[/] [risc16f84/] [trunk/] [risc16f84_clk2x.v] - Blame information for rev 8

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jclaytons
//---------------------------------------------------------------------------
2
// RISC 16F84 "clk2x" core
3
//
4
// This file is part of the "risc_16F84" project.
5
// http://www.opencores.org/cores/risc_16F84
6
// 
7
//
8
// Description: See description below (which suffices for IP core
9
//                                     specification document.)
10
//
11
// Copyright (C) 1999 Sumio Morioka (original VHDL design version)
12
// Copyright (C) 2001 John Clayton and OPENCORES.ORG (this Verilog version)
13
//
14
// NOTE: This source code is free for educational/hobby use only.  It cannot
15
// be used for commercial purposes without the consent of Microchip
16
// Technology incorporated.
17
//
18
// This source file may be used and distributed without restriction provided
19
// that this copyright statement is not removed from the file and that any
20
// derivative work contains the original copyright notice and the associated
21
// disclaimer.
22
//
23
// This source file is free software; you can redistribute it and/or modify
24
// it under the terms of the GNU Lesser General Public License as published
25
// by the Free Software Foundation;  either version 2.1 of the License, or
26
// (at your option) any later version.
27
//
28
// This source is distributed in the hope that it will be useful, but WITHOUT
29
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
30
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
31
// License for more details.
32
//
33
// You should have received a copy of the GNU Lesser General Public License
34
// along with this source.
35
// If not, download it from http://www.opencores.org/lgpl.shtml
36
//
37
//---------------------------------------------------------------------------
38
//
39
// Author: John Clayton
40
// Date  : January 29, 2002
41
//
42
// (NOTE: Date formatted as day/month/year.)
43
// Update: 29/01/02 copied this file from memory_sizer.v (pared down).
44
//                  Translated the module and signal declarations.
45
//                  Transformed the instruction wires to lowercase.
46
//                  Transformed the addressing wires to lowercase.
47
// Update: 31/01/02 Translated the instruction decoder.
48
// Update:  5/02/02 Determined that stack is simply a circular buffer of
49
//                  8 locations, 13 bits per location.  Started translating
50
//                  "main_efsm" process.  Added all code from piccore.vhd
51
//                  into this file for eventual translation.  Concluded that
52
//                  "stack_full_node" is not needed.
53
// Update:  6/02/02 Translated the "ram_i_node" if/else precedural assignment.
54
// Update:  7/02/02 Changed all := to <=, changed all '0' to 0 and '1' to 1.
55
//                  Replaced all " downto " with ":".
56
//                  Finished translating QRESET state.
57
// Update: 20/02/02 Replaced all instances of Qreset with QRESET_PP.  Also
58
//                  replaced other state designations with their new names.
59
//                  Finished translating Q1, Q2 states.
60
// Update: 22/02/02 Translated section 2-4-1-1 (aluout register)
61
// Update: 27/02/02 Replaced all "or" with "||" in if statements
62
//                  Replaced all "and" with "&&" in if statements.
63
//                  Replaced all "not" with "~" in if statements.
64
//                  Finished translating Q3,Q4 states.
65
//                  Translated output signal assignments at end of code.
66
//                  Translated interrupt trigger processes.
67
// Update: 28/02/02 Finished translation of WDT and TMR0 prescaler.
68
//                  Trimmed line length to 80 characters throughout.
69
//                  Prepared to attempt initial syntax checking.
70
//                  Cleaned up some naming conventions, and verified that
71
//                  all I/O pins have _i or _o appended in the body of the
72
//                  code.
73
// Update: 03/04/02 Changed "progdata_i" to "prog_dat_i" Also changed
74
//                  "progadr_o" to "prog_adr_o"
75
// Update: 04/04/02 Created new file "risc16f84_lite.v"  This file is reduced
76
//                  and simplified from the original "risc16f84.v" file.
77
//                  Specifically, I am removing EEPROM support, and 
78
//                  consolidating porta and portb I/O pins so that they
79
//                  are bidirectional.
80
// Update: 04/04/02 Created a new file "risc16f84_small.v"  This file is
81
//                  further reduced and simplified from "risc16f84_lite.v"
82
//                  Specifically, I am removing the prescaler, TMR0 and WDT.
83
//                  Also, I am removing support for portb interrupts, leaving
84
//                  only rb0/int as an interrupt source.  This pin will be
85
//                  the only way to wake up from the SLEEP instruction...
86
//                  Obviously, the CLEARWDT instruction will no longer do
87
//                  anything.
88
// Update: 05/04/02 Removed the "powerdown_o", "startclk_o" and "clk_o" pins
89
//                  from the small design.  Also removed "rbpu_o", so if you
90
//                  want pullups, you have to add them explicitly in the
91
//                  constraints file, and option_reg[7] doesn't control them.
92
// Update: 08/04/02 Decided to modify "risc16f84_small.v" in order to try for
93
//                  more performance (only 2 states per instruction!)
94
//                  The new file is called "risc16f84_clk2x.v"  The resulting
95
//                  code was synthesized, but not tested yet.
96
// Update: 11/04/02 Decided to remove porta and portb from this unit, and add
97
//                  instead an auxiliary bus, which is intended to allow I/O
98
//                  using an indirect approach, similar to using the FSR.
99
//                  However, the aux_adr_o is 16 bits wide, so that larger
100
//                  RAM may be accessed indirectly by the processor... The use
101
//                  of FSR for this purpose proved undesirable, since any new
102
//                  page of RAM contains "holes" to accomodate the registers
103
//                  in the first 12 locations (including FSR!) so that large
104
//                  contiguous blocks of memory could not be accessed in an
105
//                  effective way.  This auxiliary bus solves that problem.
106
//                  Since this processor is implemented inside of an FPGA,
107
//                  and it is not a goal to maintain compatibility with
108
//                  existing libraries of code, there is no need to maintain
109
//                  porta and portb in the hardware.
110
//                  The aux_adr_lo and aux_adr_hi registers are located at
111
//                  88h and 89h, and the aux_dat_io location is decoded at
112
//                  08h.
113
//                  Also, changed to using "ram_we_o" instead of "readram_o"
114
//                  and "writeram_o"
115
// Update: 16/04/02 Added clock enable signal, for processor single stepping.
116
//                  "aux_dat_io" is only driven when "clk_en_i" is high...
117
// Update: 17/04/02 Removed "reset_condition" and moved "inc_pc_node" out of
118
//                  the clocking area, making it non-registered.  In fact, I
119
//                  moved everything other than the state machine out of the
120
//                  clocked logic section.  Changed "aluout_reg" to "aluout"
121
//                  since it is no longer registered.
122
// Update: 26/04/02 Fixed bug in aluout logic.  The AND and OR functions were
123
//                  coded with logical AND/OR instead of bitwise AND/OR!
124
// Update: 26/04/02 Changed location of aux_adr_lo and aux_adr_hi registers
125
//                  to 05h and 06h, respectively.  This was done to save
126
//                  code space because when using the aux data bus, no bank
127
//                  switching is necessary since they will now reside in the
128
//                  same bank.
129
// Update: 01/05/02 Fixed another bug -- the rrf and rlf instructions were
130
//                  coded incorrectly.
131
// Update: 03/05/02 Fixed another bug -- the carry bit was incorrect (the
132
//                  problem was discovered while performing SUBWF X,W where
133
//                  W contained 0 and X contained 1. (1-0).  The logic for
134
//                  the carry bit appears to have been incorrect even in
135
//                  the original VHDL code by Sumio Morioka.
136
// Update: 11/18/02 Fixed bug in PCL addressing mode (near line 791)
137
//                  Removed parameters associated with WDT.
138
// Update: 11/25/02 Re-wrote much of the main FSM.  Attempted to generate logic
139
//                  to recognize the falling edge of an interrupt, and was
140
//                  unsuccessful (not simulation, actual hardware tests.)
141
//                  Realized that falling edge interrupt can be equivalent to
142
//                  rising edge interrupt with a NOT gate on the signal.  Since
143
//                  NOTs are practically free inside of an FPGA, decided to
144
//                  abandon the negative edge aspect of recognizing interrupts.
145
//                  Therefore, removed the "option_reg" since it is no longer
146
//                  needed in this design.
147
// Update: 08/08/03 Fixed a mathematical error, which was introduced by the bug
148
//                  fix of 03/05/02.  The fix of 03/05/02 correctly generated the
149
//                  C bit for subtraction of zero, but unfortunately it introduced
150
//                  an error such that all subtraction results were off by 1.
151
//                  Obviously, this was unacceptable, and I think it has been fixed
152
//                  by the new signals "c_subtract_zero" and "c_dig_subtract_zero"
153 4 jclaytons
// Update: 10/24/05 Added code patches to fix interrupt bug and status flag updates
154
//                  when using literal value of 0x03.  These bugs were reported by
155
//                  an opencores.org user.  Added three "disable_status_x" signals.
156 6 jclaytons
//                  Modified file still needs to be tested.
157 2 jclaytons
//
158
// Description
159
//---------------------------------------------------------------------------
160
// This logic module implements a small RISC microcontroller, with functions
161
// and instruction set very similar to those of the Microchip 16F84 chip.
162
// This work is a translation (from VHDL to Verilog) of the "CQPIC" design
163
// published in 1999 by Sumio Morioka of Japan, and published in the December
164
// 1999 issue of "Transistor Gijutsu Magazine."  The translation was performed
165
// by John Clayton, without the use of any translation tools.
166
//
167
// Original version used as basis for translation:  CQPIC version 1.00b
168
//                                                  (December 10, 2000)
169
//
170
// Further revisions and re-writing have been completed on this code by John
171
// Clayton.  The interrupt mechanism has been completely re-done, and the
172
// way in which the program counter is generated is expressed in a new way.
173
//
174
// In the comments, a "cycle" is defined as a processor cycle of 2 states.
175
// Thus, passing through states Q2_PP and Q4_PP completes one cycle.
176
// The numbers "1-3" and so forth are left from the comments in the original
177
// source code used as the basis of the translation.
178
//---------------------------------------------------------------------------
179
 
180
`define STATEBIT_SIZE 2      // Size of state machine register (bits)
181
 
182
 
183
module risc16f84_clk2x (
184
  prog_dat_i,           // [13:0] ROM read data
185
  prog_adr_o,           // [12:0] ROM address
186
  ram_dat_i,            // [7:0] RAM read data
187
  ram_dat_o,            // [7:0] RAM write data
188
  ram_adr_o,            // [8:0] RAM address; ram_adr[8:7] indicates RAM-BANK
189
  ram_we_o,             // RAM write strobe (H active)
190
  aux_adr_o,            // [15:0] Auxiliary address bus
191
  aux_dat_io,           // [7:0] Auxiliary data bus (tri-state bidirectional)
192
  aux_we_o,             // Auxiliary write strobe (H active)
193
  int0_i,               // PORT-B(0) INT
194
  reset_i,              // Power-on reset (H active)
195
  clk_en_i,             // Clock enable for all clocked logic
196
  clk_i                 // Clock input
197
);
198
 
199
 
200
// You can change the following parameters as you would like
201
parameter STACK_SIZE_PP      = 8;   // Size of PC stack
202
parameter LOG2_STACK_SIZE_PP = 3;   // Log_2(stack_size)
203
 
204
// State definitions for state machine, provided as parameters to allow
205
// for redefinition of state values by the instantiator if desired.
206
parameter Q2_PP     = 2'b00;  // state Q2
207
parameter Q4_PP     = 2'b01;  // state Q4
208
parameter QINT_PP   = 2'b10;  // interrupt state (substitute for Q4)
209
parameter QSLEEP_PP = 2'b11;  // sleep state
210
 
211
 
212
// I/O declarations
213
 
214
       // program ROM data bus/address bus
215
input  [13:0] prog_dat_i;   // ROM read data
216
output [12:0] prog_adr_o;   // ROM address
217
 
218
       // data RAM data bus/address bus/control signals
219
input  [7:0] ram_dat_i;     // RAM read data
220
output [7:0] ram_dat_o;     // RAM write data
221
output [8:0] ram_adr_o;     // RAM address; ram_adr[8:7] indicates RAM-BANK
222
output ram_we_o;            // RAM write strobe (H active)
223
 
224
       // auxiliary data bus/address bus/control signals
225
output [15:0] aux_adr_o;    // AUX address bus
226
inout  [7:0]  aux_dat_io;   // AUX data bus
227
output aux_we_o;            // AUX write strobe (H active)
228
 
229
       // interrupt input
230
input  int0_i;              // INT
231
 
232
       // CPU reset
233
input  reset_i;             // Power-on reset (H active)
234
 
235
       // CPU clock
236
input  clk_en_i;            // Clock enable input
237
input  clk_i;               // Clock input
238
 
239
 
240
// Internal signal declarations
241
 
242
     // User registers
243
reg  [7:0] w_reg;            // W
244
reg  [12:0] pc_reg;          // PCH/PCL -- Address currently being fetched
245
reg  [12:0] old_pc_reg;      // Address fetched previous to this one.
246
reg  [7:0] status_reg;       // STATUS
247
reg  [7:0] fsr_reg;          // FSR
248
reg  [4:0] pclath_reg;       // PCLATH
249
reg  [7:0] intcon_reg;       // INTCON
250
reg  [7:0] aux_adr_hi_reg;   // AUX address high byte
251
reg  [7:0] aux_adr_lo_reg;   // AUX address low byte
252
 
253
     // Internal registers for controlling instruction execution
254
reg  [13:0] inst_reg;        // Holds fetched op-code/operand
255
reg  [7:0]  aluinp1_reg;     // data source (1 of 2)
256
reg  [7:0]  aluinp2_reg;     // data source (2 of 2)
257
reg  exec_stall_reg;         // if H (i.e. after GOTO etc), stall execution.
258
 
259
     // Stack
260
                             // stack (array of data-registers)
261
reg  [12:0] stack_reg [STACK_SIZE_PP-1:0];
262
                             // stack pointer
263
reg  [LOG2_STACK_SIZE_PP-1:0] stack_pnt_reg;
264
wire [12:0] stack_top;       // More compatible with sensitivity list than
265
                             // "stack_reg[stack_pnt_reg]"
266
 
267
     // Interrupt registers/nodes
268
wire int_condition;          // Indicates that an interrupt should be recognized
269
wire intrise;                // High indicates edge was detected
270
reg  intrise_reg;            // detect positive edge of PORT-B inputs
271
     // Synchronizer for interrupt
272
reg  inte_sync_reg;
273
 
274
     // State register
275
reg  [`STATEBIT_SIZE-1:0] state_reg;
276
reg  [`STATEBIT_SIZE-1:0] next_state_node;
277
 
278
     // Result of decoding instruction -- only 1 is active at a time
279
wire inst_addlw;
280
wire inst_addwf;
281
wire inst_andlw;
282
wire inst_andwf;
283
wire inst_bcf;
284
wire inst_bsf;
285
wire inst_btfsc;
286
wire inst_btfss;
287
wire inst_call;
288
wire inst_clrf;
289
wire inst_clrw;
290
wire inst_comf;
291
wire inst_decf;
292
wire inst_decfsz;
293
wire inst_goto;
294
wire inst_incf;
295
wire inst_incfsz;
296
wire inst_iorlw;
297
wire inst_iorwf;
298
wire inst_movlw;
299
wire inst_movf;
300
wire inst_movwf;
301
wire inst_retfie;
302
wire inst_retlw;
303
wire inst_ret;
304
wire inst_rlf;
305
wire inst_rrf;
306
wire inst_sleep;
307
wire inst_sublw;
308
wire inst_subwf;
309
wire inst_swapf;
310
wire inst_xorlw;
311
wire inst_xorwf;
312
 
313
     // Result of calculating RAM access address
314
wire [8:0] ram_adr_node;      // RAM access address
315
 
316
     // These wires indicate accesses to special registers... 
317
     // Only 1 is active at a time.
318
wire addr_pcl;
319
wire addr_stat;
320
wire addr_fsr;
321
wire addr_pclath;
322
wire addr_intcon;
323
wire addr_aux_adr_lo;
324
wire addr_aux_adr_hi;
325
wire addr_aux_dat;
326
wire addr_sram;
327
 
328
     // Other output registers (for removing hazards)
329
reg  ram_we_reg;          // data-sram write strobe
330
reg  aux_we_reg;          // AUX write strobe
331
 
332
 
333
     // Signals used in "main_efsm" procedure
334
     // (Intermediate nodes used for resource sharing.)
335
wire [7:0]  ram_i_node;    // result of reading RAM/Special registers
336
wire [7:0]  mask_node;     // bit mask for logical operations
337
wire [8:0]  add_node;      // result of 8bit addition
338
wire [4:0]  addlow_node;   // result of low-4bit addition
339
wire aluout_zero_node;    // H if ALUOUT = 0
340
 
341
reg  [12:0] next_pc_node;  // value of next PC
342
reg  [7:0] aluout;        // result of calculation
343
reg  writew_node;         // H if destination is W register
344
reg  writeram_node;       // H if destination is RAM/Special registers
345
reg  c_subtract_zero;     // High for special case of C bit, when subtracting zero
346
reg  c_dig_subtract_zero; // High for special case of C bit, when subtracting zero
347
 
348
wire next_exec_stall;
349 4 jclaytons
     // Three signals used to disable status flag updates.  Fixes bug when literal 0x03 is used.
350
wire disable_status_z;
351
wire disable_status_c;
352
wire disable_status_dc;
353 2 jclaytons
 
354
//--------------------------------------------------------------------------
355
// Instantiations
356
//--------------------------------------------------------------------------
357
 
358
 
359
//--------------------------------------------------------------------------
360
// Functions & Tasks
361
//--------------------------------------------------------------------------
362
 
363
//--------------------------------------------------------------------------
364
// Module code
365
//--------------------------------------------------------------------------
366
 
367
// This represents the instruction fetch from program memory.
368
// inst_reg[13:0] stores the instruction.  This happens at the end of Q4.
369
// So the memory access time is one processor cycle (2 clocks!) minus
370
// the setup-time of this register, and minus the delay to drive the 
371
// address out onto the prog_adr_o bus.
372
always @(posedge clk_i)
373
begin
374
  if (reset_i) inst_reg <= 0;
375
  else if (clk_en_i && (state_reg == Q4_PP)) inst_reg <= prog_dat_i;
376
end
377
 
378
// NOTE: There is an extra "15th" bit of inst_reg, which represents an
379
// interrupt execution cycle.  This is included in inst_reg so that when
380
// an interrupt instruction is executing, it effectively "pre-empts" the
381
// other instructions.
382
// The fifteenth bit, inst_reg[14], is set by the interrupt logic.
383
 
384
// Decode OPcode    (see pp.54 of PIC16F84 data sheet)
385
// only 1 signal of the following signals will be '1'
386
assign inst_call    = (inst_reg[13:11] ==  3'b100           );
387
assign inst_goto    = (inst_reg[13:11] ==  3'b101           );
388
assign inst_bcf     = (inst_reg[13:10] ==  4'b0100          );
389
assign inst_bsf     = (inst_reg[13:10] ==  4'b0101          );
390
assign inst_btfsc   = (inst_reg[13:10] ==  4'b0110          );
391
assign inst_btfss   = (inst_reg[13:10] ==  4'b0111          );
392
assign inst_movlw   = (inst_reg[13:10] ==  4'b1100          );
393
assign inst_retlw   = (inst_reg[13:10] ==  4'b1101          );
394
assign inst_sublw   = (inst_reg[13:9]  ==  5'b11110         );
395
assign inst_addlw   = (inst_reg[13:9]  ==  5'b11111         );
396
assign inst_iorlw   = (inst_reg[13:8]  ==  6'b111000        );
397
assign inst_andlw   = (inst_reg[13:8]  ==  6'b111001        );
398
assign inst_xorlw   = (inst_reg[13:8]  ==  6'b111010        );
399
assign inst_subwf   = (inst_reg[13:8]  ==  6'b000010        );
400
assign inst_decf    = (inst_reg[13:8]  ==  6'b000011        );
401
assign inst_iorwf   = (inst_reg[13:8]  ==  6'b000100        );
402
assign inst_andwf   = (inst_reg[13:8]  ==  6'b000101        );
403
assign inst_xorwf   = (inst_reg[13:8]  ==  6'b000110        );
404
assign inst_addwf   = (inst_reg[13:8]  ==  6'b000111        );
405
assign inst_movf    = (inst_reg[13:8]  ==  6'b001000        );
406
assign inst_comf    = (inst_reg[13:8]  ==  6'b001001        );
407
assign inst_incf    = (inst_reg[13:8]  ==  6'b001010        );
408
assign inst_decfsz  = (inst_reg[13:8]  ==  6'b001011        );
409
assign inst_rrf     = (inst_reg[13:8]  ==  6'b001100        );
410
assign inst_rlf     = (inst_reg[13:8]  ==  6'b001101        );
411
assign inst_swapf   = (inst_reg[13:8]  ==  6'b001110        );
412
assign inst_incfsz  = (inst_reg[13:8]  ==  6'b001111        );
413
assign inst_movwf   = (inst_reg[13:7]  ==  7'b0000001       );
414
assign inst_clrw    = (inst_reg[13:7]  ==  7'b0000010       );
415
assign inst_clrf    = (inst_reg[13:7]  ==  7'b0000011       );
416
assign inst_ret     = (inst_reg[13:0]  == 14'b00000000001000);
417
assign inst_retfie  = (inst_reg[13:0]  == 14'b00000000001001);
418
assign inst_sleep   = (inst_reg[13:0]  == 14'b00000001100011);
419
 
420
 
421
// Calculate RAM access address (see pp.19 of PIC16F84 data sheet)
422
 
423
    // if "d"=0, indirect addressing is used, so RAM address is BANK+FSR
424
    // otherwise, RAM address is BANK+"d"
425
    // (see pp.19 of PIC16F84 data sheet)
426
assign ram_adr_node = (inst_reg[6:0]==0)?{status_reg[7],fsr_reg[7:0]}:
427
                               {status_reg[6:5],inst_reg[6:0]};
428
 
429
    // check if this is an access to external RAM or not
430
assign addr_sram   = (ram_adr_node[6:0] > 7'b0001011); //0CH-7FH,8CH-FFH
431
 
432
    // check if this is an access to special register or not
433
    // only 1 signal of the following signals will be '1'
434
assign addr_pcl     = (ram_adr_node[6:0] ==  7'b0000010);    // 02H, 82H
435
assign addr_stat    = (ram_adr_node[6:0] ==  7'b0000011);    // 03H, 83H
436
assign addr_fsr     = (ram_adr_node[6:0] ==  7'b0000100);    // 04H, 84H
437
assign addr_aux_dat = (ram_adr_node[7:0] == 8'b00001000);    // 08H
438
assign addr_pclath  = (ram_adr_node[6:0] ==  7'b0001010);    // 0AH, 8AH
439
assign addr_intcon  = (ram_adr_node[6:0] ==  7'b0001011);    // 0BH, 8BH
440
assign addr_aux_adr_lo = (ram_adr_node[7:0] == 8'b00000101); // 05H
441
assign addr_aux_adr_hi = (ram_adr_node[7:0] == 8'b00000110); // 06H
442
 
443
// construct bit-mask for logical operations and bit tests
444
assign mask_node = 1 << inst_reg[9:7];
445
 
446 4 jclaytons
// disable write access for status flags
447
assign disable_status_z  = (inst_addwf || inst_andwf || inst_clrf  ||
448
                            inst_clrw  || inst_comf  || inst_decf  ||
449
                            inst_incf  || inst_iorwf || inst_movf  ||
450
                            inst_subwf || inst_xorwf || inst_addlw ||
451
                            inst_andlw || inst_iorlw || inst_iorlw ||
452
                            inst_sublw || inst_xorlw) ? 1:0;
453
assign disable_status_c  = (inst_addwf || inst_subwf || inst_rlf   ||
454
                            inst_rrf   || inst_addlw || inst_sublw ) ? 1:0;
455
assign disable_status_dc = (inst_addwf || inst_subwf || inst_addlw ||
456
                            inst_sublw ) ? 1:0;
457
 
458
 
459 2 jclaytons
// Create the exec_stall signal, based on the contents of the currently
460
// executing instruction (inst_reg).  next_exec_stall reflects the state
461
// to assign to exec_stall following the conclusion of the next Q4 state.
462
// All of these instructions cause an execution stall in the next cycle
463
// because they modify the program counter, and a new value is presented
464
// for fetching during the stall cycle, during which time no instruction
465
// should be executed.
466
//
467
// The conditional instructions are given along with their conditions for
468
// execution.  If the conditions are not met, there is no stall and nothing
469
// to execute.
470
assign next_exec_stall = (
471
                             inst_goto
472
                          || inst_call
473
                          || inst_ret
474
                          || inst_retlw
475
                          || inst_retfie
476
                          || (
477
                              (inst_btfsc || inst_decfsz || inst_incfsz)
478
                              && aluout_zero_node
479
                              )
480
                          || (inst_btfss && ~aluout_zero_node)
481
                          || (addr_pcl && writeram_node)
482
                          );
483
always @(posedge clk_i)
484
begin
485
  if (reset_i) exec_stall_reg <= 0;
486
  else if (clk_en_i && (state_reg == QINT_PP)) exec_stall_reg <= 1;
487
  else if (clk_en_i && (state_reg == Q4_PP))
488
    exec_stall_reg <= (next_exec_stall && ~exec_stall_reg);
489
    // exec stall should never be generated during a stall cycle, because
490
    // a stall cycle doesn't execute anything...
491
end
492
 
493
assign stack_top = stack_reg[stack_pnt_reg];
494
// Formulate the next pc_reg value (the program counter.)
495
// During stall cycles, the pc is simply incremented...
496
always @(
497
            pc_reg
498
         or pclath_reg
499
         or aluout
500
         or stack_pnt_reg
501
         or stack_top
502
         or inst_ret
503
         or inst_retlw
504
         or inst_retfie
505
         or inst_goto
506
         or inst_call
507
         or inst_reg
508
         or writeram_node
509
         or addr_pcl
510
         or exec_stall_reg
511
         )
512
begin
513
  if (~exec_stall_reg &&(inst_ret || inst_retlw || inst_retfie))
514
    next_pc_node <= stack_top;
515
  else if (~exec_stall_reg &&(inst_goto || inst_call))
516
    next_pc_node <= {pclath_reg[4:3],inst_reg[10:0]};
517
  else if (~exec_stall_reg && (writeram_node && addr_pcl))
518
    // PCL is data-destination, but update the entire PC.
519
    next_pc_node <= {pclath_reg[4:0],aluout};
520
  else
521
    next_pc_node <= pc_reg + 1;
522
end
523
 
524
// Set the program counter
525
// If the sleep instruction is executing, then the PC is not allowed to be
526
// updated, since the processor will "freeze" and the instruction being fetched
527
// during the sleep instruction must be executed upon wakeup interrupt.
528
// Obviously, if the PC were to change at the end of the sleep instruction, then
529
// a different (incorrect) address would be fetched during the sleep time.
530
always @(posedge clk_i)
531
begin
532
  if (reset_i) begin
533
    pc_reg <= 0;
534
    old_pc_reg <= 0;
535
  end
536
  else if (clk_en_i && (state_reg == QINT_PP))
537
  begin
538
    old_pc_reg <= pc_reg;
539
    pc_reg <= 4;
540
  end
541
  else if (clk_en_i && ~inst_sleep && (state_reg == Q4_PP))
542
  begin
543
    old_pc_reg <= pc_reg;
544
    pc_reg <= next_pc_node;
545
  end
546
end
547
 
548
// 1. Intermediate nodes for resource sharing
549
 
550
// Tri-state drivers instead of a huge selector...  It produces smaller
551
// results, and runs faster.
552
assign ram_i_node = (addr_sram)       ?ram_dat_i:8'bZ;
553
assign ram_i_node = (addr_pcl)        ?pc_reg[7:0]:8'bZ;
554
assign ram_i_node = (addr_stat)       ?status_reg:8'bZ;
555
assign ram_i_node = (addr_fsr)        ?fsr_reg:8'bZ;
556
assign ram_i_node = (addr_aux_dat)    ?aux_dat_io:8'bZ;
557
assign ram_i_node = (addr_pclath)     ?{3'b0,pclath_reg}:8'bZ;
558
assign ram_i_node = (addr_intcon)     ?intcon_reg:8'bZ;
559
assign ram_i_node = (addr_aux_adr_lo) ?aux_adr_lo_reg:8'bZ;
560
assign ram_i_node = (addr_aux_adr_hi) ?aux_adr_hi_reg:8'bZ;
561
 
562
// 1-3. Adder (ALU)
563
// full 8bit-addition, with carry in/out.
564
// Note that "temp" and "dtemp" are intended to be thrown away.
565
// Also, addlow_node[3:0] are thrown away.
566
// Even though they are assigned, they should never be used.
567
assign add_node     =    {1'b0,aluinp1_reg}
568
                       + {1'b0,aluinp2_reg};
569
// lower 4bit-addition
570
assign addlow_node =    {1'b0,aluinp1_reg[3:0]}
571
                      + {1'b0,aluinp2_reg[3:0]};
572
 
573
// 1-4. Test if aluout = 0
574
assign aluout_zero_node = (aluout == 0)?1:0;
575
 
576
// 1-5. Determine destination
577
always @(
578
            inst_reg
579
         or inst_movwf
580
         or inst_bcf
581
         or inst_bsf
582
         or inst_clrf
583
         or inst_movlw
584
         or inst_addlw
585
         or inst_sublw
586
         or inst_andlw
587
         or inst_iorlw
588
         or inst_xorlw
589
         or inst_retlw
590
         or inst_clrw
591
         or inst_movf
592
         or inst_swapf
593
         or inst_addwf
594
         or inst_subwf
595
         or inst_andwf
596
         or inst_iorwf
597
         or inst_xorwf
598
         or inst_decf
599
         or inst_incf
600
         or inst_rlf
601
         or inst_rrf
602
         or inst_decfsz
603
         or inst_incfsz
604
         or inst_comf
605
         )
606
begin
607
  if (inst_movwf || inst_bcf || inst_bsf || inst_clrf)
608
  begin
609
    writew_node     <= 0;
610
    writeram_node   <= 1;
611
  end
612
  else if (   inst_movlw || inst_addlw || inst_sublw || inst_andlw
613
           || inst_iorlw || inst_xorlw || inst_retlw || inst_clrw)
614
  begin
615
    writew_node     <= 1;
616
    writeram_node   <= 0;
617
  end
618
  else if (   inst_movf   || inst_swapf || inst_addwf || inst_subwf
619
           || inst_andwf  || inst_iorwf || inst_xorwf || inst_decf
620
           || inst_incf   || inst_rlf   || inst_rrf   || inst_decfsz
621
           || inst_incfsz || inst_comf)
622
  begin
623
    writew_node     <= ~inst_reg[7];  // ("d" field of fetched instruction)
624
    writeram_node   <=  inst_reg[7];  // ("d" field of fetched instruction)
625
  end
626
  else
627
  begin
628
    writew_node     <= 0;
629
    writeram_node   <= 0;
630
  end
631
end // End of determine destination logic
632
 
633
 
634
 
635
 
636
// 2-4-1. Calculation and store result into alu-output register
637
 
638
always @(
639
            add_node
640
         or aluinp1_reg
641
         or aluinp2_reg
642
         or status_reg
643
         or inst_reg
644
         or inst_movwf
645
         or inst_bcf
646
         or inst_bsf
647
         or inst_btfsc
648
         or inst_btfss
649
         or inst_clrf
650
         or inst_addlw
651
         or inst_sublw
652
         or inst_andlw
653
         or inst_iorlw
654
         or inst_xorlw
655
         or inst_retlw
656
         or inst_clrw
657
         or inst_swapf
658
         or inst_addwf
659
         or inst_subwf
660
         or inst_andwf
661
         or inst_iorwf
662
         or inst_xorwf
663
         or inst_decf
664
         or inst_incf
665
         or inst_rlf
666
         or inst_rrf
667
         or inst_decfsz
668
         or inst_incfsz
669
         or inst_comf
670
         )
671
begin
672
  // 2-4-1-1. Set aluout register
673
          // Rotate left
674
  if      (inst_rlf)
675
          aluout <= {aluinp1_reg[6:0],status_reg[0]};
676
          // Rotate right
677
  else if (inst_rrf)
678
          aluout  <= {status_reg[0],aluinp1_reg[7:1]};
679
          // Swap nibbles
680
  else if (inst_swapf)
681
          aluout <= {aluinp1_reg[3:0],aluinp1_reg[7:4]};
682
          // Logical inversion
683
  else if (inst_comf)
684
          aluout  <= ~aluinp1_reg;
685
          // Logical AND, bit clear/bit test
686
  else if (   inst_andlw || inst_andwf || inst_bcf || inst_btfsc
687
           || inst_btfss)
688
          aluout  <= (aluinp1_reg & aluinp2_reg);
689
          // Logical OR, bit set
690
  else if (inst_bsf || inst_iorlw || inst_iorwf)
691
          aluout  <= (aluinp1_reg | aluinp2_reg);
692
          // Logical XOR
693
  else if (inst_xorlw || inst_xorwf)
694
          aluout  <= (aluinp1_reg ^ aluinp2_reg);
695
          // Addition, Subtraction, Increment, Decrement
696
  else if (  inst_addlw || inst_addwf  || inst_sublw || inst_subwf
697
           || inst_decf || inst_decfsz || inst_incf  || inst_incfsz)
698
          aluout  <= add_node[7:0];
699
          // Pass through
700
  else aluout  <= aluinp1_reg;
701
end
702
 
703
 
704
// MAIN EFSM: description of register value changes in each clock cycle
705
always @(posedge clk_i)
706
begin
707
  // Assign reset (default) values of registers
708
  if (reset_i)
709
  begin
710
    status_reg[7:5] <= 3'b0;
711
    pclath_reg      <= 0;     // 0
712
    intcon_reg[7:1] <= 7'b0;
713
    aux_adr_lo_reg  <= 0;
714
    aux_adr_hi_reg  <= 0;
715
    ram_we_reg      <= 0;
716
    status_reg[4]   <= 1;     // /T0 = 1
717
    status_reg[3]   <= 1;     // /PD = 1
718
    stack_pnt_reg   <= 0;     // Reset stack pointer
719
  end  // End of reset assignments
720
  else if (~exec_stall_reg && clk_en_i)
721
  begin   // Execution ceases during a stall cycle.
722
    if (state_reg == Q2_PP) // 2-3. Q2 cycle
723
    begin
724
      // 2-3-1. Read data-RAM and store values to alu-input regs
725
      // 2-3-1-1. Set aluinp1 register (source #1)
726
      if (   inst_movf   || inst_swapf || inst_addwf || inst_subwf
727
          || inst_andwf  || inst_iorwf || inst_xorwf || inst_decf
728
          || inst_incf   || inst_rlf   || inst_rrf   || inst_bcf
729
          || inst_bsf    || inst_btfsc || inst_btfss || inst_decfsz
730
          || inst_incfsz || inst_comf)
731
 
732
          aluinp1_reg <= ram_i_node;       // RAM/Special registers
733
      else
734
      if (   inst_movlw || inst_addlw || inst_sublw || inst_andlw
735
          || inst_iorlw || inst_xorlw || inst_retlw)
736
          aluinp1_reg <= inst_reg[7:0];    // Immediate value ("k")
737
      else
738
      if (   inst_clrf  || inst_clrw) aluinp1_reg <= 0; // 0
739
      else aluinp1_reg <= w_reg;                        // W register
740
 
741
      // 2-3-1-2. Set aluinp2 register (source #2)
742
      c_subtract_zero <= 0;       // default to non-special case
743
      c_dig_subtract_zero <= 0;   // default to non-special case
744
      if      (inst_decf || inst_decfsz) aluinp2_reg <= -1; // for decr.
745
      else if (inst_incf || inst_incfsz) aluinp2_reg <=  1; // for incr.
746
              // -1 * W register (for subtract)
747
      else if (inst_sublw || inst_subwf)
748
      begin
749
        aluinp2_reg <= ~w_reg + 1;
750
        c_subtract_zero <= (w_reg == 0);            // Indicate special case
751
        c_dig_subtract_zero <= (w_reg[3:0] == 0);   // Indicate special case
752
      end
753
            // operation of BCF: AND with inverted mask ("1..101..1")
754
            // mask for BCF: value of only one position is 0
755
      else if (inst_bcf) aluinp2_reg <= ~mask_node;
756
            // operation of BSF: OR with mask_node ("0..010..0")
757
            // operation of FSC and FSS: AND with mask_node, compare to 0
758
      else if (inst_btfsc || inst_btfss || inst_bsf)
759
                                  aluinp2_reg <= mask_node;
760
      else aluinp2_reg <= w_reg; // W register
761
 
762
      // 2-3-1-3. Set stack pointer register (pop stack)
763
      if (inst_ret || inst_retlw || inst_retfie)
764
           stack_pnt_reg   <= stack_pnt_reg - 1; // cycles 3,2,1,0,7,6...
765
 
766
      // 2-4-1-3. Set data-SRAM write enable (hazard-free)
767
      // Set the write enables depending on the destination.
768
      // (These have been implemented as registers to avoid glitches?
769
      // It is not known to me (John Clayton) whether any glitches would
770
      // really occur.  It might be possible to generate these signals
771
      // using combinational logic only, without using registers!
772
      ram_we_reg <= (writeram_node && addr_sram);
773
      aux_we_reg <= (writeram_node && addr_aux_dat);
774
    end   // End of Q2 state
775
 
776
    //---------------------------------------------------------------------
777
 
778
    else if (state_reg == QINT_PP) // Interrupt execution (instead of Q4_PP)
779
    begin
780
        // PORT-B0 INT
781
        intcon_reg[1] <= 1;                     // set INTF
782
        intcon_reg[7] <= 0;                     // clear GIE
783
        stack_reg[stack_pnt_reg] <= old_pc_reg; // Push old PC
784
        stack_pnt_reg <= stack_pnt_reg + 1;     // increment stack pointer
785
        // The old PC is pushed, so that the pre-empted instruction can be
786
        // restarted later, when the retfie is executed.
787
    end
788
 
789
    //---------------------------------------------------------------------
790
 
791
    else if (state_reg == Q4_PP)   // Execution & writing of results.
792
    begin
793
 
794
      if (inst_call)
795
      begin
796
        stack_reg[stack_pnt_reg] <= pc_reg;     // Push current PC
797
        stack_pnt_reg <= stack_pnt_reg + 1;     // increment stack pointer
798
      end
799
 
800
      if (inst_retfie) // "return from interrupt" instruction
801
      begin
802
        intcon_reg[7] <= 1;                     // Set GIE
803
      end
804
 
805
      // 2-4-1-2. Set C flag and DC flag
806
      if (inst_addlw || inst_addwf || inst_sublw || inst_subwf)
807
      begin
808
        // c_dig_subtract_zero and c_subtract_zero are used to take care of the
809
        // special case when subtracting zero, where the carry bit should be 1
810
        // (meaning no borrow).  It is explicitly set by these signals during
811
        // that condition.  See 16F84 datasheet, page 8 for further information
812
        // about the C bit.
813
        status_reg[1]   <= addlow_node[4] || c_dig_subtract_zero;  // DC flag
814
        status_reg[0]   <= add_node[8] || c_subtract_zero;         // C flag
815
      end
816
      else if (inst_rlf) status_reg[0] <= aluinp1_reg[7];  // C flag
817
      else if (inst_rrf) status_reg[0] <= aluinp1_reg[0];  // C flag
818
 
819
      // 2-5-2. Store calculation result into destination, 
820
      // 2-5-2-1. Set W register
821
 
822
      if (writew_node) w_reg   <= aluout;    // write W reg
823
 
824 4 jclaytons
 
825 2 jclaytons
      // 2-5-2-2. Set data RAM/special registers,
826
      if (writeram_node)
827
      begin
828
        if (addr_stat)
829
        begin
830
          status_reg[7:5] <= aluout[7:5];      // write IRP,RP1,RP0
831
          // status(4),status(3)...unwritable, see below (/PD,/T0 part)
832 4 jclaytons
          if( ~disable_status_c ) status_reg[0] <= aluout[0]; // write C
833
          if( ~disable_status_dc ) status_reg[1] <= aluout[1]; // write DC
834 2 jclaytons
        end
835
        if (addr_fsr)         fsr_reg <= aluout;       // write FSR
836
        if (addr_pclath)   pclath_reg <= aluout[4:0];  // write PCLATH
837
        if (addr_intcon) intcon_reg <= aluout;         // write INTCON
838
        if (addr_aux_adr_lo) aux_adr_lo_reg <= aluout; // write AUX low
839
        if (addr_aux_adr_hi) aux_adr_hi_reg <= aluout; // write AUX high
840
      end
841
 
842
      // 2-5-2-3. Set/clear Z flag.
843 4 jclaytons
      if (addr_stat && ~disable_status_z) status_reg[2] <= aluout[2];
844 2 jclaytons
      else if (   inst_addlw || inst_addwf || inst_andlw || inst_andwf
845
               || inst_clrf  || inst_clrw  || inst_comf  || inst_decf
846
               || inst_incf  || inst_movf  || inst_sublw || inst_subwf
847
               || inst_xorlw || inst_xorwf || inst_iorlw || inst_iorwf )
848
              status_reg[2] <= aluout_zero_node; // Z=1 if result == 0
849
 
850
      // 2-5-3. Clear RAM write enables (hazard-free)
851
      ram_we_reg <= 0;
852
      aux_we_reg <= 0;
853
 
854
    end    // End of Q4 state
855
  end // End of "if (~exec_stall_reg)"    
856
end  // End of process
857
 
858
 
859
// Calculation of next processor state.
860
// (Not including reset conditions, which are covered by the clocked logic,
861
//  which also includes a "global clock enable."
862
always @(
863
            state_reg
864
         or inst_sleep
865
         or inte_sync_reg
866
         or exec_stall_reg
867
         or int_condition
868
         )
869
begin
870
  case (state_reg)
871
  Q2_PP     : if (int_condition) next_state_node <= QINT_PP;
872
              else next_state_node <= Q4_PP;
873
  Q4_PP     : if (~exec_stall_reg && inst_sleep) next_state_node <= QSLEEP_PP;
874
              else next_state_node <= Q2_PP;
875
  QINT_PP   : next_state_node <= Q2_PP;
876
  QSLEEP_PP : if (inte_sync_reg) next_state_node <= Q2_PP;
877
              else next_state_node <= QSLEEP_PP;
878
              // Default condition provided for convention and completeness
879
              // only.  Logically, all of the conditions are already covered.
880
  default   : next_state_node <= Q2_PP;
881
  endcase
882
end
883
 
884
 
885
// Clocked state transitions, based upon dataflow (non-clocked logic) in
886
// the previous always block.
887
always @(posedge clk_i)
888
begin
889
  if (reset_i) state_reg <= Q2_PP;
890
  else if (clk_en_i) state_reg <= next_state_node;
891
end  // End of process
892
 
893
 
894
// Detect external interrupt requests
895
// You can code multiple interrupts if you wish, or use the single interrupt
896
// provided and simply have the interrupt service routine (ISR) check to find
897
// out the source of the interrupt, by or-ing together all of the interrupt
898
// sources and providing a readable register of their values at the time
899
// the interrupt occurred.
900
//
901
// When an interrupt is recognized by the processor, this is signified by
902
// entering "QINT_PP," which is treated like an executable instruction.
903
// The interrupt instruction can only be executed when not in a stall condition.
904
// It simply "pre-empts" the instruction that would have been executed during
905
// that cycle.  Then, when retfie is executed, the pre-empted instruction is
906
// re-started (the stall cycle of the retfie is when the address of the 
907
// instruction being re-started is fetched.)
908
//
909
// I was unable to obtain correct operation for capturing the negative edge,
910
// so I am discarding it.  If one really needs to generate an interrupt on the
911
// falling edge, just use an inverted version of the signal (the inversion is
912
// often "free" inside of an FPGA anyhow.)
913
//
914
// Upon further testing, I discovered that even the rising edge "trigger" was not
915
// really truly an edge detection, it was more like a "set-reset" flip flop
916
// type of behavior.  Rather than mess around with it any more, I am implementing
917
// a clocked "poor man's rising edge detector."
918
// Capture the rising edge of the interrupt input...  This part is self clearing.
919
// It also means that the interrupt must last longer than one clock cycle in
920
// order to be properly recognized.  (It is "pseudo edge triggered", not a true
921
// rising edge trigger.)
922
// When the interrupt is recognized, inte_sync_reg is cleared.
923
 
924
 
925
always @(posedge clk_i)
926
begin
927
  if (clk_en_i) intrise_reg <= int0_i;
928
end // process
929
assign intrise = (int0_i && ~intrise_reg);
930
 
931
//  The inte_sync_reg signal is used for waking up from SLEEP.
932
//  (this flip flop is also a synchronizer to minimize the
933
//   possibility of metastability due to changes at the input
934
//   occurring at the same time as the processor clock edge...)
935
//  It might be possible to eliminate this step, and issue the interrupt
936
//  directly without this intermediate synchronizer flip-flop.
937
always @(posedge clk_i)
938
begin
939
  if (reset_i || (state_reg == QINT_PP)) inte_sync_reg <= 0;
940
  else if (clk_en_i && intrise && intcon_reg[4]) inte_sync_reg <= 1;
941
end
942
 
943
// Issue an interrupt when the interrupt is present.
944
// Also, do not issue an interrupt when there is a stall cycle coming!
945 4 jclaytons
assign int_condition = (inte_sync_reg && ~exec_stall_reg && ~next_exec_stall && intcon_reg[7]);
946 2 jclaytons
                               // Interrupt must be pending
947
                               // Next processor cycle must not be a stall
948
                               // GIE bit must be set to issue interrupt
949
 
950
// Circuit's output signals
951
assign prog_adr_o = pc_reg;        // program ROM address
952
assign ram_adr_o  = ram_adr_node;  // data RAM address
953
assign ram_dat_o  = aluout;        // data RAM write data
954
assign ram_we_o   = ram_we_reg;    // data RAM write enable
955
 
956
assign aux_adr_o  = {aux_adr_hi_reg,aux_adr_lo_reg};
957
assign aux_dat_io = (aux_we_reg && clk_en_i)?aluout:{8{1'bZ}};
958
assign aux_we_o   = aux_we_reg;
959
 
960
endmodule
961
 
962
 
963
//`undef STATEBIT_SIZE

powered by: WebSVN 2.1.0

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