Porting lcc


32-bit RISC CPU >>
<< Soft cores

Usenet Postings
  By Subject
  By Date

  Why FPGA CPUs?
  Homebuilt processors
  Altera, Xilinx Announce
  Soft cores
  Porting lcc
  32-bit RISC CPU
  Superscalar FPGA CPUs
  Java processors
  Forth processors
  Reimplementing Alto
  FPGA CPU Speeds
  Synthesized CPUs
  Register files
  Register files (2)
  Floating point
  Using block RAM
  Flex10K CPUs
  Flex10KE CPUs

  Multis and fast unis
  Inner loop datapaths

  SoC On-Chip Buses
  On-chip Memory
  VGA controller
  Small footprints

  CNets and Datapaths
  Generators vs. synthesis

FPGAs vs. Processors
  CPUs vs. FPGAs
  Emulating FPGAs
  FPGAs as coprocessors
  Regexps in FPGAs
  Life in an FPGA
  Maximum element

  Pushing on a rope
  Virtex speculation
  Rambus for FPGAs
  3-D rendering
  LFSR Design

Google SiteSearch
Subject: Re: porting a compiler to a new architecture
Date: 22 Mar 1999 00:00:00 GMT
Newsgroups: comp.compilers

mathai-@ecf.toronto.edu wrote ...
>I'm designing a RISC CPU for fun, and wanted to know how difficult it
>would be to port a compiler like gcc to generate code (non-optimized is
>fine) for my machine? I'm ignorant of compilers, but can learn .. I'd just
>like to assess how difficult it would be.
>[One RISC is pretty much like another for a straightforward code generator,
>so I'd think you should be able to get a limping version of lcc in a week
>or two. -John]

I recently designed another RISC CPU for fun.  This one is a 16-bit
16-register classic pipelined RISC, implemented using Xilinx Student Ed.,
occupying about 60% of a Xilinx XC4005XL-3 FPGA, running at 25 MHz.

I targeted lcc 4.1 to this new processor and was quite pleased with the
process and the results.  Most of the work was done in one long and very
pleasant day.  However, I had already read Fraser and Hanson [1], and I used
to write compilers.  So your mileage may vary.

(I look forward to trying the same thing with GCC.)

Here's what I did.  I downloaded lcc4.1 from
www.cs.princeton.edu/software/lcc and built it with MS VC++.  I read
doc/4.html, "The lcc 4.1 Code-Generation Interface".

Since I was targeting a classic RISC instruction set architecture, I started
with the MIPS machine description, mips.md.  I copied that to xr16.md, added
xr16.md to the makefile, and added two lines to bind.c for "-target=xr16".

Next I designed xr16 register conventions (below) and modified my md to
target these registers.

Register Use
r0 always zero
r1 reserved for assembler
r2 function return value
r3-r5 function arguments
r6-r9 temporaries
r10-r13 register variables
r14 stack pointer (sp)
r15 return address

At this point I had a C compiler for a 32-bit 16-register RISC.  But I
needed to target a 16-bit machine with sizeof(int)=sizeof(void*)=2.  No
problem!  Lcc obtains target operand sizes from md tables -- so, change some
4's to 2's:

Interface xr16IR = {
        1, 1, 0,  /* char */
        2, 2, 0,  /* short */
        2, 2, 0,  /* int */
        4, 4, 0,  /* long */
        2, 2, 0,  /* T * */

Next I built and ran the "ops" utility "ops c=1 s=2 i=2 l=4 h=4 f=4 d=4 x=4
p=2" which prints the required primitive dag operator set for a machine with
2-byte ints and pointers.  I modified my instruction templates to cover this
operator set, and removed some 32-bit int assumptions inherited from

(This small effort compared extremely favorably with past experience of
porting another C/C++ compiler from 16-bit ints/pointers to 32-bit

I decided to keep long ints in register pairs.  This required just four
lines of code to introduce a new class of register resource and to target
the 4-byte integer types to that resource.  Wow.  (Although this hasn't had
much testing yet.)

Compared to the MIPS templates, my xr16 templates reflect
* different branch scheme (condition codes, sorry);
* logic/shift instructions are (necessarily) two-operand only;
* immediate constants are encoded differently;
* mul, div, and rem are calls upon helper routines.

All totaled, in xr16.md, I replaced the entire dag operator set (entirely
generated by ops utility), changed about 200 lines of instruction templates
(mostly to reflect 2-byte int/pointer changes in dag operator types), and
about 100 lines of miscellaneous code.

I have yet to properly diagnose use of floating point (never to be
implemented).  And except for some test apps, I haven't properly tested the

The resulting code quality?  Not superlative, but not too bad.  For example,
for this source:

typedef struct TN {
  int k;
  struct TN *left, *right;
} *T;

T search(int k, T p) {
  while (p && p->k != k)
    if (p->k < k)
      p = p->right;
      p = p->left;
  return p;

my "lcc -S -Wf-target=xr16 search.c" emits this assembler:

align 16
br L3
lw r9,(r4)
cmp r9,r3
bge L5
lw r4,4(r4)
br L6
lw r4,2(r4)
mov r9,r4
cmp r9,r0
beq L7
lw r9,(r4)
cmp r9,r3
bne L2
mov r2,r4

which I consider quite acceptable for my purposes.

I only wish there was a retargetable assembler as easy to port as is lcc.  I
looked at gas but it seemed rather large.  Any pointers?  Instead I wrote a
simple two-pass assembler from scratch.  This took twice as long as the
compiler port...

Jan Gray

[1] Christopher W. Fraser, David R. Hanson.  A Retargetable C Compiler :
Design and Implementation.  Addison-Wesley. ISBN: 0805316701

Copyright © 2000, Gray Research LLC. All rights reserved.
Last updated: Feb 03 2001