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

Subversion Repositories risc16f84

[/] [risc16f84/] [web_uploads/] [risc16f84_small.v] - Blame information for rev 9

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 9 root
//---------------------------------------------------------------------------
2
// RISC 16F84 "small" 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: 26/04/02 Fixed bug in aluout_reg logic, so that bitwise operators
93
//                  are used for AND/OR.  (They had been wrongly coded using
94
//                  logical operators!)
95
// Update: 01/05/02 Fixed another bug -- the rrf and rlf instructions were
96
//                  coded incorrectly.
97
// Update: 03/05/02 Fixed another bug -- the carry bit was incorrect (the
98
//                  problem was discovered while performing SUBWF X,W where
99
//                  W contained 0 and X contained 1. (1-0).  The logic for
100
//                  the carry bit appears to have been incorrect even in
101
//                  the original VHDL code by Sumio Morioka.
102
// Update: 10/30/02 Fixed syntax error pointed out by Cheol-Kyoo Lee, who got
103
//                  the source code from opencores.com.  Removed semicolon
104
//                  from "endcase" statements.
105
//
106
// Description
107
//---------------------------------------------------------------------------
108
// This logic module implements a small RISC microcontroller, with functions
109
// and instruction set very similar to those of the Microchip 16F84 chip.
110
// This work is a translation (from VHDL to Verilog) of the "CQPIC" design
111
// published in 1999 by Sumio Morioka of Japan, and published in the December
112
// 1999 issue of "Transistor Gijutsu Magazine."  The translation was performed
113
// by John Clayton, without the use of any translation tools.
114
//
115
// Original version used as basis for translation:  CQPIC version 1.00b
116
//                                                  (December 10, 2000)
117
//---------------------------------------------------------------------------
118
 
119
`define STATEBIT_SIZE 3      // Size of state machine register (bits)
120
 
121
 
122
module risc16f84_small (
123
  prog_dat_i,           // [13:0] ROM read data
124
  prog_adr_o,           // [12:0] ROM address
125
  ram_dat_i,            // [7:0] RAM read data
126
  ram_dat_o,            // [7:0] RAM write data
127
  ram_adr_o,            // [8:0] RAM address; ram_adr[8:7] indicates RAM-BANK
128
  readram_o,            // RAM read strobe (H active)
129
  writeram_o,           // RAM write strobe (H active)
130
  porta_io,             // [4:0] PORT-A
131
  portb_io,             // [7:0] PORT-B
132
  int0_i,               // PORT-B(0) INT
133
  pon_rst_n_i,          // Power-on reset (L active)
134
  clk_i                 // Clock input
135
);
136
 
137
 
138
// You can change the following parameters as you would like
139
parameter STACK_SIZE_PP      = 8;   // Size of PC stack
140
parameter LOG2_STACK_SIZE_PP = 3;   // Log_2(stack_size)
141
parameter WDT_SIZE_PP        = 255; // Size of watch dog timer (WDT)
142
parameter WDT_BITS_PP        = 8;   // Bits needed for watch dog timer (WDT)
143
 
144
// State definitions for state machine, provided as parameters to allow
145
// for redefinition of state values by the instantiator if desired.
146
parameter QRESET_PP = 3'b100; // reset state
147
parameter Q1_PP     = 3'b000; // state Q1
148
parameter Q2_PP     = 3'b001; // state Q2
149
parameter Q3_PP     = 3'b011; // state Q3
150
parameter Q4_PP     = 3'b010; // state Q4
151
 
152
 
153
// I/O declarations
154
 
155
       // program ROM data bus/address bus
156
input  [13:0] prog_dat_i;   // ROM read data
157
output [12:0] prog_adr_o;   // ROM address
158
 
159
       // data RAM data bus/address bus/control signals
160
input  [7:0] ram_dat_i;     // RAM read data
161
output [7:0] ram_dat_o;     // RAM write data
162
output [8:0] ram_adr_o;     // RAM address; ram_adr[8:7] indicates RAM-BANK
163
output readram_o;           // RAM read  strobe (H active)
164
output writeram_o;          // RAM write strobe (H active)
165
 
166
       // I/O ports
167
inout  [4:0] porta_io;      // PORT-A
168
inout  [7:0] portb_io;      // PORT-B
169
 
170
       // PORT-B interrupt input
171
input  int0_i;              // PORT-B(0) INT
172
 
173
       // CPU reset
174
input  pon_rst_n_i;         // Power-on reset (LOW active)
175
 
176
       // CPU clock
177
input  clk_i;               // Clock input
178
 
179
 
180
// Internal signal declarations
181
 
182
     // User registers
183
reg  [7:0] w_reg;            // W
184
reg  [12:0] pc_reg;          // PCH/PCL
185
reg  [7:0] status_reg;       // STATUS
186
reg  [7:0] fsr_reg;          // FSR
187
reg  [4:0] porta_i_sync_reg; // PORTA IN (synchronizer)
188
reg  [4:0] porta_o_reg;      // PORTA OUT
189
reg  [7:0] portb_i_sync_reg; // PORTB IN (synchronizer)
190
reg  [7:0] portb_o_reg;      // PORTB OUT
191
reg  [4:0] pclath_reg;       // PCLATH
192
reg  [7:0] intcon_reg;       // INTCON
193
reg  [7:0] option_reg;       // OPTION
194
reg  [4:0] trisa_reg;        // TRISA
195
reg  [7:0] trisb_reg;        // TRISB
196
 
197
     // Internal registers for controlling instruction execution
198
reg  [13:0] inst_reg;        // Hold fetched op-code/operand
199
reg  [7:0] aluinp1_reg;      // data source (1 of 2)
200
reg  [7:0] aluinp2_reg;      // data source (2 of 2)
201
reg        c_in;             // Used with ALU data sources.
202
reg  [7:0] aluout_reg;       // result of calculation
203
reg  exec_op_reg;            // if L (i.e. GOTO instruction etc), stall exec.
204
reg  intstart_reg;           // if H (i.e. interrupt), stall instr. exec.
205
reg  sleepflag_reg;          // if H, sleeping.
206
 
207
     // Stack
208
                             // stack (array of data-registers)
209
reg  [12:0] stack_reg [STACK_SIZE_PP-1:0];
210
                             // stack pointer (binary encoded)
211
reg  [LOG2_STACK_SIZE_PP-1:0] stack_pnt_reg;
212
 
213
     // Interrupt registers/nodes
214
reg  intrise_reg;            // detect positive edge of PORT-B inputs
215
reg  intdown_reg;            // detect negative edge of PORT-B inputs
216
 
217
wire rb0_int;                // Interrupt trigger
218
 
219
wire inte;                    // RB0   interrupt trigger
220
reg  intclr_reg;              // CPU; clear intrise_reg and intdown_reg
221
 
222
     // State register
223
reg  [`STATEBIT_SIZE-1:0] state_reg;
224
 
225
     // Result of decoding instruction -- only 1 is active at a time
226
wire inst_addlw;
227
wire inst_addwf;
228
wire inst_andlw;
229
wire inst_andwf;
230
wire inst_bcf;
231
wire inst_bsf;
232
wire inst_btfsc;
233
wire inst_btfss;
234
wire inst_call;
235
wire inst_clrf;
236
wire inst_clrw;
237
wire inst_comf;
238
wire inst_decf;
239
wire inst_decfsz;
240
wire inst_goto;
241
wire inst_incf;
242
wire inst_incfsz;
243
wire inst_iorlw;
244
wire inst_iorwf;
245
wire inst_movlw;
246
wire inst_movf;
247
wire inst_movwf;
248
wire inst_retfie;
249
wire inst_retlw;
250
wire inst_ret;
251
wire inst_rlf;
252
wire inst_rrf;
253
wire inst_sleep;
254
wire inst_sublw;
255
wire inst_subwf;
256
wire inst_swapf;
257
wire inst_xorlw;
258
wire inst_xorwf;
259
 
260
     // Result of calculating RAM access address
261
wire [8:0] ram_adr_node;      // RAM access address
262
 
263
     // These wires indicate accesses to special registers... 
264
     // Only 1 is active at a time.
265
wire addr_pcl;
266
wire addr_stat;
267
wire addr_fsr;
268
wire addr_porta;
269
wire addr_portb;
270
wire addr_pclath;
271
wire addr_intcon;
272
wire addr_option;
273
wire addr_trisa;
274
wire addr_trisb;
275
wire addr_sram;
276
 
277
     // Other output registers (for removing hazards)
278
reg  writeram_reg;      // data-sram write strobe
279
reg  [8:0] ram_adr_reg; // data-sram address
280
 
281
     // Synchronizers
282
reg  inte_sync_reg;
283
reg  reset_condition;
284
 
285
     // Signals used in "main_efsm" procedure
286
     // (Intermediate nodes used for resource sharing.)
287
reg  [7:0] ram_i_node;   // result of reading RAM/Special registers
288
reg  [12:0] inc_pc_node; // value of PC + 1
289
wire [7:0] mask_node;    // bit mask for logical operations
290
reg  [8:0] add_node;     // result of 8bit addition
291
reg  [4:0] addlow_node;  // result of low-4bit addition
292
wire temp;               // Placeholder wire
293
wire dtemp;              // Placeholder wire
294
reg  aluout_zero_node;   // H if ALUOUT = 0
295
reg  writew_node;        // H if destination is W register
296
reg  writeram_node;      // H if destination is RAM/Special registers
297
reg  int_node;           // H if interrupt request comes
298
 
299
//--------------------------------------------------------------------------
300
// Instantiations
301
//--------------------------------------------------------------------------
302
 
303
 
304
//--------------------------------------------------------------------------
305
// Functions & Tasks
306
//--------------------------------------------------------------------------
307
 
308
function [7:0] bitwise_tristate;
309
  input [7:0] port;
310
  input [7:0] tris;
311
  integer k;
312
  begin
313
    for (k=0; k<8; k=k+1) bitwise_tristate[k] <= (tris[k])?1'bZ:port[k];
314
  end
315
endfunction
316
 
317
 
318
//--------------------------------------------------------------------------
319
// Module code
320
//--------------------------------------------------------------------------
321
 
322
 
323
// CPU synchronizers
324
always @(posedge clk_i)
325
begin
326
  inte_sync_reg   <= inte;
327
  reset_condition <= ~pon_rst_n_i;
328
end
329
 
330
 
331
// Decode OPcode    (see pp.54 of PIC16F84 data sheet)
332
// only 1 signal of the following signals will be '1'
333
assign inst_call     = (inst_reg[13:11] ==  3'b100           );
334
assign inst_goto     = (inst_reg[13:11] ==  3'b101           );
335
assign inst_bcf      = (inst_reg[13:10] ==  4'b0100          );
336
assign inst_bsf      = (inst_reg[13:10] ==  4'b0101          );
337
assign inst_btfsc    = (inst_reg[13:10] ==  4'b0110          );
338
assign inst_btfss    = (inst_reg[13:10] ==  4'b0111          );
339
assign inst_movlw    = (inst_reg[13:10] ==  4'b1100          );
340
assign inst_retlw    = (inst_reg[13:10] ==  4'b1101          );
341
assign inst_sublw    = (inst_reg[13:9]  ==  5'b11110         );
342
assign inst_addlw    = (inst_reg[13:9]  ==  5'b11111         );
343
assign inst_iorlw    = (inst_reg[13:8]  ==  6'b111000        );
344
assign inst_andlw    = (inst_reg[13:8]  ==  6'b111001        );
345
assign inst_xorlw    = (inst_reg[13:8]  ==  6'b111010        );
346
assign inst_subwf    = (inst_reg[13:8]  ==  6'b000010        );
347
assign inst_decf     = (inst_reg[13:8]  ==  6'b000011        );
348
assign inst_iorwf    = (inst_reg[13:8]  ==  6'b000100        );
349
assign inst_andwf    = (inst_reg[13:8]  ==  6'b000101        );
350
assign inst_xorwf    = (inst_reg[13:8]  ==  6'b000110        );
351
assign inst_addwf    = (inst_reg[13:8]  ==  6'b000111        );
352
assign inst_movf     = (inst_reg[13:8]  ==  6'b001000        );
353
assign inst_comf     = (inst_reg[13:8]  ==  6'b001001        );
354
assign inst_incf     = (inst_reg[13:8]  ==  6'b001010        );
355
assign inst_decfsz   = (inst_reg[13:8]  ==  6'b001011        );
356
assign inst_rrf      = (inst_reg[13:8]  ==  6'b001100        );
357
assign inst_rlf      = (inst_reg[13:8]  ==  6'b001101        );
358
assign inst_swapf    = (inst_reg[13:8]  ==  6'b001110        );
359
assign inst_incfsz   = (inst_reg[13:8]  ==  6'b001111        );
360
assign inst_movwf    = (inst_reg[13:7]  ==  7'b0000001       );
361
assign inst_clrw     = (inst_reg[13:7]  ==  7'b0000010       );
362
assign inst_clrf     = (inst_reg[13:7]  ==  7'b0000011       );
363
assign inst_ret      = (inst_reg[13:0]  == 14'b00000000001000);
364
assign inst_retfie   = (inst_reg[13:0]  == 14'b00000000001001);
365
assign inst_sleep    = (inst_reg[13:0]  == 14'b00000001100011);
366
 
367
 
368
// Calculate RAM access address (see pp.19 of PIC16F84 data sheet)
369
 
370
    // if "d"=0, indirect addressing is used, so RAM address is BANK+FSR
371
    // otherwise, RAM address is BANK+"d"
372
    // (see pp.19 of PIC16F84 data sheet)
373
assign ram_adr_node = (inst_reg[6:0]==0)?{status_reg[7],fsr_reg[7:0]}:
374
                               {status_reg[6:5],inst_reg[6:0]};
375
 
376
    // check if this is an access to external RAM or not
377
assign addr_sram   = (ram_adr_node[6:0] > 7'b0001011); //0CH-7FH,8CH-FFH
378
 
379
    // check if this is an access to special register or not
380
    // only 1 signal of the following signals will be '1'
381
assign addr_pcl     = (ram_adr_node[6:0] ==  7'b0000010); // 02H, 82H
382
assign addr_stat    = (ram_adr_node[6:0] ==  7'b0000011); // 03H, 83H
383
assign addr_fsr     = (ram_adr_node[6:0] ==  7'b0000100); // 04H, 84H
384
assign addr_porta   = (ram_adr_node[7:0] == 8'b00000101); // 05H
385
assign addr_portb   = (ram_adr_node[7:0] == 8'b00000110); // 06H
386
assign addr_pclath  = (ram_adr_node[6:0] ==  7'b0001010); // 0AH, 8AH
387
assign addr_intcon  = (ram_adr_node[6:0] ==  7'b0001011); // 0BH, 8BH
388
assign addr_option  = (ram_adr_node[7:0] == 8'b10000001); // 81H
389
assign addr_trisa   = (ram_adr_node[7:0] == 8'b10000101); // 85H
390
assign addr_trisb   = (ram_adr_node[7:0] == 8'b10000110); // 86H
391
 
392
// construct bit-mask for logical operations and bit tests
393
assign mask_node = 1 << inst_reg[9:7];
394
 
395
// MAIN EFSM: description of register value changes in each clock cycle
396
always @(posedge clk_i)
397
begin
398
  // 1. Intermediate nodes for resource sharing
399
 
400
  // This is a long if/else chain.  Consider pulling in the decoded signals
401
  // addr_tmr0 etc., and using a case statement instead?
402
  // 1-1. Reading RAM/data sources  (see pp.13 of PIC16F84 data sheet)
403
  if (addr_sram)         ram_i_node <= ram_dat_i;   // data from ext. SRAM
404
  else if (addr_pcl)     ram_i_node <= pc_reg[7:0]; // data from pcl
405
  else if (addr_stat)    ram_i_node <= status_reg;  // data from status
406
  else if (addr_fsr)     ram_i_node <= fsr_reg;     // data from fsr
407
  else if (addr_porta)
408
  begin
409
    // Logic implements a 2:1 mux for each bit [4:0] of ram_i_node
410
    ram_i_node[4:0] <= (
411
                           (~trisa_reg[4:0] & porta_o_reg[4:0])
412
                        || ( trisa_reg[4:0] & porta_i_sync_reg[4:0])
413
                        );
414
    ram_i_node[7:5] <= 3'b0;
415
  end
416
  else if (addr_portb)
417
  begin
418
    // Logic implements a 2:1 mux for each bit [7:0] of ram_i_node
419
    ram_i_node[7:0] <= (
420
                           (~trisb_reg[7:0] & portb_o_reg[7:0])
421
                        || ( trisb_reg[7:0] & portb_i_sync_reg[7:0])
422
                        );
423
  end
424
  else if (addr_pclath)  ram_i_node <= {3'b0,pclath_reg}; // pclath (5bit)
425
  else if (addr_intcon)  ram_i_node <= intcon_reg;        // data from intcon
426
  else if (addr_option)  ram_i_node <= option_reg;        // data from option
427
  else if (addr_trisa)   ram_i_node <= {3'b0,trisa_reg};  // trisa (5bit)
428
  else if (addr_trisb)   ram_i_node <= trisb_reg;         // data from trisb
429
  else ram_i_node <= 0;
430
 
431
 
432
  // 1-2. PC + 1
433
  inc_pc_node  <= pc_reg + 1;
434
 
435
  // 1-3. Adder (ALU)
436
  // full 8bit-addition, with carry in/out.
437
  {add_node,temp}     <=    {1'b0,aluinp1_reg,1'b1}
438
                          + {1'b0,aluinp2_reg,c_in};
439
  // lower 4bit-addition
440
  {addlow_node,dtemp} <=    {1'b0,aluinp1_reg[3:0],1'b1}
441
                          + {1'b0,aluinp2_reg[3:0],c_in};
442
 
443
  // 1-4. Test if aluout = 0
444
  aluout_zero_node <= (aluout_reg == 0)?1:0;
445
 
446
  // 1-5. Determine destination
447
  if (intstart_reg)
448
  begin
449
    writew_node     <= 0;
450
    writeram_node   <= 0;
451
  end
452
  else if (inst_movwf || inst_bcf || inst_bsf || inst_clrf)
453
  begin
454
    writew_node     <= 0;
455
    writeram_node   <= 1;
456
  end
457
  else if (   inst_movlw || inst_addlw || inst_sublw || inst_andlw
458
           || inst_iorlw || inst_xorlw || inst_retlw || inst_clrw)
459
  begin
460
    writew_node     <= 1;
461
    writeram_node   <= 0;
462
  end
463
  else if (   inst_movf   || inst_swapf || inst_addwf || inst_subwf
464
           || inst_andwf  || inst_iorwf || inst_xorwf || inst_decf
465
           || inst_incf   || inst_rlf   || inst_rrf   || inst_decfsz
466
           || inst_incfsz || inst_comf)
467
  begin
468
    writew_node     <= ~inst_reg[7];  // ("d" field of fetched instruction)
469
    writeram_node   <=  inst_reg[7];  // ("d" field of fetched instruction)
470
  end
471
  else
472
  begin
473
    writew_node     <= 0;
474
    writeram_node   <= 0;
475
  end
476
 
477
  // 1-6. Interrupt request   (see pp.17 of PIC16F84 data sheet)
478
  int_node <= intcon_reg[7]        // GIE
479
              && (intcon_reg[4] && intcon_reg[1]); // INTE,INTF
480
 
481
  // 2. EFSM body
482
  case (state_reg)
483
 
484
    // 2-1. Reset state (see pp.14 and pp.42 of PIC16F84 data sheet)
485
    QRESET_PP :
486
    begin
487
      pc_reg          <= 0;     // 0
488
      status_reg[7:5] <= 3'b0;
489
      pclath_reg      <= 0;     // 0
490
      intcon_reg[7:1] <= 7'b0;
491
      option_reg      <= -1;    // Set to all ones, like vhdl (others => 1)
492
      trisa_reg       <= -1;    // Set to all ones, like vhdl (others => 1)
493
      trisb_reg       <= -1;    // Set to all ones, like vhdl (others => 1)
494
      exec_op_reg     <= 0;
495
      intclr_reg      <= 1;     // clear int
496
      intstart_reg    <= 0;
497
      writeram_reg    <= 0;
498
      sleepflag_reg   <= 0;
499
      status_reg[4]   <= 1;     // /T0 = 1
500
      status_reg[3]   <= 1;     // /PD = 1
501
      stack_pnt_reg   <= 0;     // Reset stack pointer
502
 
503
      // go to Q1 state if reset signal is de-asserted
504
      if (~reset_condition) state_reg <= Q1_PP;
505
 
506
    end  // End of QRESET_PP state
507
 
508
 
509
    // 2-2. Q1 cycle
510
    Q1_PP :
511
    begin
512
      // 2-2-1. Clear external interrupt registers if GIE=0
513
      if (intcon_reg[7]) intclr_reg <= 0;
514
      else intclr_reg <= 1;     // clear interrupt
515
 
516
      // 2-2-2. Read I/O port
517
      porta_i_sync_reg <= porta_io;
518
      portb_i_sync_reg <= portb_io;
519
 
520
      // 2-2-3. Read RAM read address, if not stalled
521
      if (exec_op_reg && ~intstart_reg) ram_adr_reg <= ram_adr_node;
522
 
523
      // 2-2-5. Goto next cycle
524
      if (reset_condition) state_reg <= QRESET_PP;
525
      else
526
        // if in the sleep mode, wait until wake-up trigger comes
527
        if (sleepflag_reg && ~intstart_reg)
528
        begin
529
          if (inte_sync_reg)
530
          begin
531
          // if rb0/inte interrupt comes, then resume execution
532
            sleepflag_reg <= 0;
533
            state_reg     <= Q2_PP;
534
          end
535
        end
536
        // if not in sleep mode, or if stalled, continue execution
537
        else state_reg   <= Q2_PP;
538
 
539
// Alternate rendition of 2-2-5...
540
//      // 2-2-5. Goto next cycle
541
//      if (reset_condition) state_reg <= QRESET_PP; // Reset
542
//      else if (~sleepflag_reg) state_reg <= Q2_PP; // Not sleeping, move on
543
//      else if (intstart_reg)   state_reg <= Q2_PP; // Stalled, move on
544
//      else if (~inte_sync_reg) state_reg <= Q1_PP; // No wakeup, stay sleeping
545
//      else // Not stalled and wake-up trigger comes...
546
//      begin
547
//        // if rb0/int interrupt comes, then resume execution
548
//        sleepflag_reg <= 0;    // Exit sleep mode condition
549
//        state_reg     <= Q2_PP;
550
//      end
551
 
552
 
553
    end   // End of Q1 state
554
 
555
    // 2-3. Q2 cycle
556
    Q2_PP :
557
    begin
558
      // 2-3-1. Read data-RAM and substitute source values to alu-input regs
559
      if (exec_op_reg && ~intstart_reg)  // if NOT STALLED
560
      begin
561
        // 2-3-1-1. Set aluinp1 register (source #1)
562
        if (   inst_movf   || inst_swapf || inst_addwf || inst_subwf
563
            || inst_andwf  || inst_iorwf || inst_xorwf || inst_decf
564
            || inst_incf   || inst_rlf   || inst_rrf   || inst_bcf
565
            || inst_bsf    || inst_btfsc || inst_btfss || inst_decfsz
566
            || inst_incfsz || inst_comf)
567
 
568
            aluinp1_reg <= ram_i_node;       // RAM/Special registers
569
        else
570
        if (   inst_movlw || inst_addlw || inst_sublw || inst_andlw
571
            || inst_iorlw || inst_xorlw || inst_retlw)
572
 
573
            aluinp1_reg <= inst_reg[7:0];    // Immediate value ("k")
574
        else
575
        if (   inst_clrf  || inst_clrw) aluinp1_reg <= 0; // 0
576
        else aluinp1_reg <= w_reg;                        // W register
577
 
578
        // 2-3-1-2. Set aluinp2 register (source #2)
579
        if      (inst_decf || inst_decfsz) aluinp2_reg <= -1; // for decr.
580
        else if (inst_incf || inst_incfsz) aluinp2_reg <=  1; // for incr.
581
                // -1 * W register (for subtract)
582
        else if (inst_sublw || inst_subwf) aluinp2_reg <= ~w_reg + 1;
583
                // operation of BCF: AND with inverted mask ("1..101..1")
584
                // mask for BCF: value of only one position is 0
585
        else if (inst_bcf) aluinp2_reg <= ~mask_node;
586
                // operation of BSF: OR with mask_node ("0..010..0")
587
                // operation of FSC and FSS: AND with mask_node, compare to 0
588
        else if (inst_btfsc || inst_btfss || inst_bsf)
589
                                      aluinp2_reg <= mask_node;
590
        else aluinp2_reg <= w_reg; // W register
591
 
592
        // 2-3-1-3. Set stack pointer register (pop stack)
593
        if (inst_ret || inst_retlw || inst_retfie)
594
             stack_pnt_reg   <= stack_pnt_reg - 1; // cycles 3,2,1,0,7,6...
595
 
596
        // 2-3-1-4. Set ram_adr register (set RAM write address)
597
        ram_adr_reg  <= ram_adr_node;     // RAM write address
598
      end
599
 
600
      // 2-3-4. Goto next cycle
601
      if (reset_condition) state_reg <= QRESET_PP;
602
      else state_reg <= Q3_PP;
603
    end   // End of Q2 state
604
 
605
    // 2-4. Q3 cycle
606
    Q3_PP :
607
    begin
608
      // 2-4-1. Calculation and store result into alu-output register
609
      if (exec_op_reg && ~intstart_reg) // if NOT STALLED
610
      begin
611
        // 2-4-1-1. Set aluout register
612
                // Rotate left
613
        if      (inst_rlf)
614
                aluout_reg <= {aluinp1_reg[6:0],status_reg[0]};
615
                // Rotate right
616
        else if (inst_rrf)
617
                aluout_reg  <= {status_reg[0],aluinp1_reg[7:1]};
618
                // Swap nibbles
619
        else if (inst_swapf)
620
                aluout_reg <= {aluinp1_reg[3:0],aluinp1_reg[7:4]};
621
                // Logical inversion
622
        else if (inst_comf)
623
                aluout_reg  <= ~aluinp1_reg;
624
                // Logical AND, bit clear/bit test
625
        else if (   inst_andlw || inst_andwf || inst_bcf || inst_btfsc
626
                 || inst_btfss)
627
                aluout_reg  <= (aluinp1_reg & aluinp2_reg);
628
                // Logical OR, bit set
629
        else if (inst_bsf || inst_iorlw || inst_iorwf)
630
                aluout_reg  <= (aluinp1_reg | aluinp2_reg);
631
                // Logical XOR
632
        else if (inst_xorlw || inst_xorwf)
633
                aluout_reg  <= (aluinp1_reg ^ aluinp2_reg);
634
                // Addition, Subtraction, Increment, Decrement
635
        else if (  inst_addlw || inst_addwf  || inst_sublw || inst_subwf
636
                 || inst_decf || inst_decfsz || inst_incf  || inst_incfsz)
637
                aluout_reg  <= add_node[7:0];
638
                // Pass through
639
        else aluout_reg  <= aluinp1_reg;
640
 
641
        // 2-4-1-2. Set C flag and DC flag
642
        if (inst_addlw || inst_addwf || inst_sublw || inst_subwf)
643
        begin
644
          status_reg[1]   <= addlow_node[4];          // DC flag
645
          status_reg[0]   <= add_node[8];             // C flag
646
        end
647
        else if (inst_rlf) status_reg[0] <= aluinp1_reg[7];  // C flag
648
        else if (inst_rrf) status_reg[0] <= aluinp1_reg[0];  // C flag
649
 
650
        // 2-4-1-3. Set data-SRAM write enable (hazard-free)
651
        if (writeram_node && addr_sram) writeram_reg <= 1;
652
        else writeram_reg <= 0;
653
 
654
      end
655
      else writeram_reg <= 0; // If stalled
656
 
657
      // 2-4-2. Check external interrupt and set int. flag
658
      if (~intstart_reg && intcon_reg[7]) // GIE
659
      begin
660
        // PORT-B0 INT
661
        if (inte_sync_reg)
662
        begin
663
          intcon_reg[1] <= 1;     // set INTF
664
          intclr_reg    <= 1;     // clear external int-register
665
                                  // (intrise_reg and intdown_reg)
666
        end
667
      end
668
 
669
      // 2-4-3. Goto next cycle
670
      if (reset_condition) state_reg   <= QRESET_PP;
671
      else            state_reg   <= Q4_PP;
672
 
673
    end    // End of Q3 state
674
 
675
 
676
    // 2-5. Q4 cycle
677
    Q4_PP :
678
    begin
679
      // 2-5-1. Fetch next program-instruction
680
      inst_reg    <= prog_dat_i;
681
 
682
      if (~exec_op_reg && ~intstart_reg)      // if STALLED (not interrupt) 
683
      begin
684
        pc_reg          <= inc_pc_node; // increment PC
685
        exec_op_reg     <= 1;           // end of stall
686
      end
687
      else  // if NOT stalled 
688
      begin
689
        // (note: if intstart_reg, only stack/pc-operations in this 
690
        //        else-clause will be performed)
691
        // 2-5-2. Store calculation result into destination, 
692
        // set PC and flags, and determine if execute next cycle.
693
 
694
        // 2-5-2-1. Set W register, if not in stall cycle 
695
        //          (~intstart_reg) and destination is W
696
 
697
        // writew_node == 0 if intstart_reg...
698
        if (writew_node) w_reg   <= aluout_reg;    // write W reg
699
 
700
        // 2-5-2-2. Set data RAM/special registers,
701
        // if not in stall cycle (~intstart_reg)
702
        if (writeram_node)
703
        begin
704
          if (addr_stat)
705
          begin
706
            status_reg[7:5] <= aluout_reg[7:5];      // write IRP,RP1,RP0
707
            // status(4),status(3)...unwritable, see below (/PD,/T0 part)
708
            status_reg[1:0] <= aluout_reg[1:0];      // write DC,C
709
          end
710
          if (addr_fsr)         fsr_reg <= aluout_reg;      // write FSR
711
          if (addr_porta)   porta_o_reg <= aluout_reg[4:0]; // write PORT-A
712
          if (addr_portb)   portb_o_reg <= aluout_reg;      // write PORT-B
713
          if (addr_pclath)   pclath_reg <= aluout_reg[4:0]; // write PCLATH
714
          if (addr_intcon) intcon_reg[6:0] <= aluout_reg[6:0];
715
                           // write INTCON (except GIE)
716
                           // intcon(7)...see below (GIE part)
717
          if (addr_option)   option_reg <= aluout_reg;      // write OPTION
718
          if (addr_trisa)     trisa_reg <= aluout_reg[4:0]; // write TRISA
719
          if (addr_trisb)     trisb_reg <= aluout_reg;      // write TRISB
720
        end
721
 
722
        // 2-5-2-3. Set/clear Z flag, if not in stall cycle (~intstart_reg)
723
        if (~intstart_reg)
724
        begin
725
          if (addr_stat) status_reg[2] <= aluout_reg[2]; // (dest. is Z flag)
726
          else if (   inst_addlw || inst_addwf || inst_andlw || inst_andwf
727
                   || inst_clrf  || inst_clrw  || inst_comf  || inst_decf
728
                   || inst_incf  || inst_movf  || inst_sublw || inst_subwf
729
                   || inst_xorlw || inst_xorwf || inst_iorlw || inst_iorwf )
730
                  status_reg[2] <= aluout_zero_node; // Z=1 if result == 0
731
        end
732
 
733
        // 2-5-2-4. Set PC and determine whether to execute next cycle or not
734
        // After interrupt-stall cycle ends, jump to interrupt vector
735
        if (intstart_reg)
736
        begin
737
          pc_reg      <= 4;     // (interrupt vector)
738
          exec_op_reg <= 0;     // the next cycle is a stall cycle
739
        end
740
        else if (inst_ret || inst_retlw || inst_retfie) // "return" instr.
741
        begin
742
          pc_reg      <= stack_reg[stack_pnt_reg];
743
          exec_op_reg <= 0;              // the next cycle is stall cycle
744
        end
745
        else if (inst_goto || inst_call) // "goto/call" instructions
746
        begin
747
          // (see pp.18 of PIC16F84 data sheet)
748
          pc_reg      <= {pclath_reg[4:3],inst_reg[10:0]};
749
          exec_op_reg <= 0;
750
        end
751
        else if ( (   (inst_btfsc || inst_decfsz || inst_incfsz)
752
                       && aluout_zero_node)
753
                   || (inst_btfss && ~aluout_zero_node)
754
                   ) // bit_test instrcutions
755
        begin
756
          pc_reg      <= inc_pc_node;
757
          exec_op_reg <= 0;
758
          // the next cycle is stall cycle, if test conditions are met.
759
        end
760
        else if (writeram_node && addr_pcl) // PCL is data-destination
761
        begin
762
          // (see pp.18 of PIC16F84 data sheet)
763
          pc_reg      <= pclath_reg[4:0] & aluout_reg;
764
          exec_op_reg <= 0;
765
        end
766
        else
767
        begin
768
          // this check MUST be located AFTER the above if/else sentences
769
          // check if interrupt trigger comes
770
          if (~int_node) pc_reg <= inc_pc_node;
771
          // if not, the next instr. fetch/exec. will be performed normally
772
          else pc_reg <= pc_reg;
773
          // if so, value of PC must be held 
774
          //(will be pushed onto stack at the end of next instruction cycle)
775
          exec_op_reg <= 1;
776
        end
777
 
778
        // 2-5-2-5. Push current PC value into stack, if necessary
779
        if (inst_call || intstart_reg)
780
        // CALL instr. or End of interrupt-stall cycle
781
        begin
782
          stack_reg[stack_pnt_reg] <= pc_reg;  // write PC value
783
          stack_pnt_reg <= stack_pnt_reg + 1;  // increment stack pointer
784
        end
785
 
786
        // 2-5-2-6. Set GIE bit in intcon register (intcon_reg(7))
787
        if (~intstart_reg)
788
        begin
789
          if (int_node) // interrupt trigger comes
790
          begin
791
            intcon_reg[7] <= 0; // clear GIE
792
            intstart_reg  <= 1; // the next cycle is interrupt-stall cycle
793
          end
794
          else if (inst_retfie) // "return from interrupt" instruction
795
          begin
796
            intcon_reg[7] <= 1;
797
            intstart_reg  <= 0;
798
          end
799
          else if (writeram_node && addr_intcon) // destination is GIE
800
          begin
801
            intcon_reg[7] <= aluout_reg[7];
802
            intstart_reg  <= 0;
803
          end
804
          else intstart_reg <= 0;
805
        end
806
        else intstart_reg <= 0;
807
 
808
        // 2-5-2-7. Enter sleep mode if needed. (No need to set /TO and /PD)
809
        if (~intstart_reg && inst_sleep) sleepflag_reg <= 1;
810
 
811
      end // (if not stalled)
812
 
813
      // 2-5-3. Clear data-SRAM write enable (hazard-free)
814
      writeram_reg <= 0;
815
 
816
      // 2-5-6. Goto next cycle
817
      if (reset_condition) state_reg   <= QRESET_PP;
818
      else state_reg   <= Q1_PP;
819
    end    // End of Q4 state
820
 
821
    // 2-6. Illegal states (NEVER REACHED in normal execution)
822
    default : state_reg   <= QRESET_PP;      // goto reset state
823
    endcase
824
end  // End of process
825
 
826
 
827
// Detect external interrupt requests
828
// INT0 I/F
829
always @(posedge int0_i or posedge intclr_reg)
830
begin
831
  if (intclr_reg) intrise_reg <= 0;
832
  else intrise_reg <= 1; // catch positive edge
833
end // process
834
 
835
always @(negedge int0_i or posedge intclr_reg)
836
begin
837
  if (intclr_reg) intdown_reg <= 0;
838
  else intdown_reg <= 1; // catch negative edge
839
end // process
840
assign rb0_int = option_reg[6]?intrise_reg:intdown_reg;
841
 
842
// Decode INT triggers 
843
// (do not AND with GIE(intcon_reg(7)), since these signals are 
844
//  also used for waking up from SLEEP)
845
assign inte  = intcon_reg[4] && rb0_int;                                       // G0IE and raw-trigger signal
846
 
847
 
848
// Circuit's output signals
849
assign prog_adr_o = pc_reg;        // program ROM address
850
assign ram_adr_o  = ram_adr_reg;   // data RAM address
851
assign ram_dat_o  = aluout_reg;    // data RAM write data
852
assign readram_o  = (state_reg[1:0] == Q2_PP[1:0]); // data RAM read enable 
853
                                               //(1 when state_reg = Q2_PP)
854
assign writeram_o = writeram_reg;  // data RAM write enable
855
 
856
assign porta_io   = bitwise_tristate(porta_o_reg, trisa_reg); // PORT-A
857
assign portb_io   = bitwise_tristate(portb_o_reg, trisb_reg); // PORT-B
858
 
859
endmodule
860
 
861
 
862
//`undef STATEBIT_SIZE

powered by: WebSVN 2.1.0

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