URL
https://opencores.org/ocsvn/light52/light52/trunk
Subversion Repositories light52
Compare Revisions
- This comparison shows the changes necessary to convert path
/light52
- from Rev 3 to Rev 4
- ↔ Reverse comparison
Rev 3 → Rev 4
/trunk/tools/build_opcode_table/opcode_info.txt
0,0 → 1,256
00 1 NOP |
01 2 AJMP addr11 |
02 3 LJMP addr16 |
03 1 RR A |
04 1 INC A |
05 2 INC dir |
06 1 INC @R0 |
07 1 INC @R1 |
08 1 INC R0 |
09 1 INC R1 |
0A 1 INC R2 |
0B 1 INC R3 |
0C 1 INC R4 |
0D 1 INC R5 |
0E 1 INC R6 |
0F 1 INC R7 |
10 3 JBC bit |
11 2 ACALL addr11 |
12 3 LCALL addr16 |
13 1 RRC A |
14 1 DEC A |
15 2 DEC dir |
16 1 DEC @R0 |
17 1 DEC @R1 |
18 1 DEC R0 |
19 1 DEC R1 |
1A 1 DEC R2 |
1B 1 DEC R3 |
1C 1 DEC R4 |
1D 1 DEC R5 |
1E 1 DEC R6 |
1F 1 DEC R7 |
20 3 JB bit |
21 2 AJMP addr11 |
22 1 RET |
23 1 RL A |
24 2 ADD A, #imm |
25 2 ADD A, dir |
26 1 ADD A, @R0 |
27 1 ADD A, @R1 |
28 1 ADD A, R0 |
29 1 ADD A, R1 |
2A 1 ADD A, R2 |
2B 1 ADD A, R3 |
2C 1 ADD A, R4 |
2D 1 ADD A, R5 |
2E 1 ADD A, R6 |
2F 1 ADD A, R7 |
30 3 JNB bit |
31 2 ACALL addr11 |
32 1 RETI |
33 1 RLC A |
34 2 ADDC A, #imm |
35 2 ADDC A, dir |
36 1 ADDC A, @R0 |
37 1 ADDC A, @R1 |
38 1 ADDC A, R0 |
39 1 ADDC A, R1 |
3A 1 ADDC A, R2 |
3B 1 ADDC A, R3 |
3C 1 ADDC A, R4 |
3D 1 ADDC A, R5 |
3E 1 ADDC A, R6 |
3F 1 ADDC A, R7 |
40 2 JC offset |
41 2 AJMP addr11 |
42 2 ORL dir, A |
43 3 ORL dir, #imm |
44 2 ORL A, #imm |
45 2 ORL A, dir |
46 1 ORL A, @R0 |
47 1 ORL A, @R1 |
48 1 ORL A, R0 |
49 1 ORL A, R1 |
4A 1 ORL A, R2 |
4B 1 ORL A, R3 |
4C 1 ORL A, R4 |
4D 1 ORL A, R5 |
4E 1 ORL A, R6 |
4F 1 ORL A, R7 |
50 2 JNC offset |
51 2 ACALL addr11 |
52 2 ANL dir, A |
53 3 ANL dir, #imm |
54 2 ANL A, #imm |
55 2 ANL A, dir |
56 1 ANL A, @R0 |
57 1 ANL A, @R1 |
58 1 ANL A, R0 |
59 1 ANL A, R1 |
5A 1 ANL A, R2 |
5B 1 ANL A, R3 |
5C 1 ANL A, R4 |
5D 1 ANL A, R5 |
5E 1 ANL A, R6 |
5F 1 ANL A, R7 |
60 2 JZ offset |
61 2 AJMP addr11 |
62 2 XRL dir, A |
63 3 XRL dir, #imm |
64 2 XRL A, #imm |
65 2 XRL A, dir |
66 1 XRL A, @R0 |
67 1 XRL A, @R1 |
68 1 XRL A, R0 |
69 1 XRL A, R1 |
6A 1 XRL A, R2 |
6B 1 XRL A, R3 |
6C 1 XRL A, R4 |
6D 1 XRL A, R5 |
6E 1 XRL A, R6 |
6F 1 XRL A, R7 |
70 2 JNZ offset |
71 2 ACALL addr11 |
72 2 ORL C, bit |
73 1 JMP @A+DPTR |
74 2 MOV A, #imm |
75 3 MOV dir, #imm |
76 2 MOV @R0, #imm |
77 2 MOV @R1, #imm |
78 2 MOV R0, #imm |
79 2 MOV R1, #imm |
7A 2 MOV R2, #imm |
7B 2 MOV R3, #imm |
7C 2 MOV R4, #imm |
7D 2 MOV R5, #imm |
7E 2 MOV R6, #imm |
7F 2 MOV R7, #imm |
80 2 SJMP offset |
81 2 AJMP addr11 |
82 2 ANL C, bit |
83 1 MOVC A, @A+PC |
84 1 DIV AB |
85 3 MOV dir, dir |
86 2 MOV dir, @R0 |
87 2 MOV dir, @R1 |
88 2 MOV dir, R0 |
89 2 MOV dir, R1 |
8A 2 MOV dir, R2 |
8B 2 MOV dir, R3 |
8C 2 MOV dir, R4 |
8D 2 MOV dir, R5 |
8E 2 MOV dir, R6 |
8F 2 MOV dir, R7 |
90 3 MOV DPTR, #imm |
91 2 ACALL addr11 |
92 2 MOV bit, C |
93 1 MOVC A, @A+DPTR |
94 2 SUBB A, #imm |
95 2 SUBB A, dir |
96 1 SUBB A, @R0 |
97 1 SUBB A, @R1 |
98 1 SUBB A, R0 |
99 1 SUBB A, R1 |
9A 1 SUBB A, R2 |
9B 1 SUBB A, R3 |
9C 1 SUBB A, R4 |
9D 1 SUBB A, R5 |
9E 1 SUBB A, R6 |
9F 1 SUBB A, R7 |
A0 2 ORL C, /bit |
A1 2 AJMP addr11 |
A2 2 MOV C, bit |
A3 1 INC DPTR |
A4 1 MUL AB |
A5 1 (NOP) |
A6 2 MOV @R0, dir |
A7 2 MOV @R1, dir |
A8 2 MOV R0, dir |
A9 2 MOV R1, dir |
AA 2 MOV R2, dir |
AB 2 MOV R3, dir |
AC 2 MOV R4, dir |
AD 2 MOV R5, dir |
AE 2 MOV R6, dir |
AF 2 MOV R7, dir |
B0 2 ANL C, /bit |
B1 2 ACALL addr11 |
B2 2 CPL bit |
B3 1 CPL C |
B4 3 CJNE A, #imm |
B5 3 CJNE A, dir |
B6 3 CJNE @R0, #imm |
B7 3 CJNE @R1, #imm |
B8 3 CJNE R0, #imm |
B9 3 CJNE R1, #imm |
BA 3 CJNE R2, #imm |
BB 3 CJNE R3, #imm |
BC 3 CJNE R4, #imm |
BD 3 CJNE R5, #imm |
BE 3 CJNE R6, #imm |
BF 3 CJNE R7, #imm |
C0 2 PUSH dir |
C1 2 AJMP addr11 |
C2 2 CLR bit |
C3 1 CLR C |
C4 1 SWAP A |
C5 2 XCH A, dir |
C6 1 XCH A, @R0 |
C7 1 XCH A, @R1 |
C8 1 XCH A, R0 |
C9 1 XCH A, R1 |
CA 1 XCH A, R2 |
CB 1 XCH A, R3 |
CC 1 XCH A, R4 |
CD 1 XCH A, R5 |
CE 1 XCH A, R6 |
CF 1 XCH A, R7 |
D0 2 POP dir |
D1 2 ACALL addr11 |
D2 2 SETB bit |
D3 1 SETB C |
D4 1 DA A |
D5 3 DJNZ dir |
D6 1 XCHD A, @R0 |
D7 1 XCHD A, @R1 |
D8 2 DJNZ R0 |
D9 2 DJNZ R1 |
DA 2 DJNZ R2 |
DB 2 DJNZ R3 |
DC 2 DJNZ R4 |
DD 2 DJNZ R5 |
DE 2 DJNZ R6 |
DF 2 DJNZ R7 |
E0 1 MOVX A, @DPTR |
E1 2 AJMP addr11 |
E2 1 MOVX A, @R0 |
E3 1 MOVX A, @R1 |
E4 1 CLR A |
E5 2 MOV A, dir |
E6 1 MOV A, @R0 |
E7 1 MOV A, @R1 |
E8 1 MOV A, R0 |
E9 1 MOV A, R1 |
EA 1 MOV A, R2 |
EB 1 MOV A, R3 |
EC 1 MOV A, R4 |
ED 1 MOV A, R5 |
EE 1 MOV A, R6 |
EF 1 MOV A, R7 |
F0 1 MOVX @DPTR, A |
F1 2 ACALL addr11 |
F2 1 MOVX @R0, A |
F3 1 MOVX @R1, A |
F4 1 CPL A |
F5 2 MOV dir, A |
F6 1 MOV @R0, A |
F7 1 MOV @R1, A |
F8 1 MOV R0, A |
F9 1 MOV R1, A |
FA 1 MOV R2, A |
FB 1 MOV R3, A |
FC 1 MOV R4, A |
FD 1 MOV R5, A |
FE 1 MOV R6, A |
FF 1 MOV R7, A |
/trunk/tools/build_opcode_table/svg_op_table.py
0,0 → 1,302
#!/usr/bin/env python |
""" |
svg_op_table.py: Build 3 SVG files with the MCS51 opcode table decorated with |
cycle count information extracted from the cycle count simulation log file. |
""" |
__author__ = "Jose A. Ruiz" |
__license__ = "LGPL" |
|
|
import sys |
import getopt |
|
|
def read_cycle_info(filename): |
""" |
the file should have 256 lines of text. |
Each line has 4 comma-separated fields: |
opcode, minimum cycle count, maximum cycle count, number of executions. |
The number of executions is the number of times the opcode was executed by |
the simulation that produced the log. |
If this number is zero, or if the minimum cycle count is >= 999, then |
the opcode has not been executed and there's no cycle count data for it. |
|
This function returns a list of 256 tuples sorted by opcode, with the |
above 3 values (the opcode is excluded). |
""" |
|
# Open file and read it into a list of lines. |
fin = open(filename, "r") |
lines = fin.readlines() |
fin.close() |
|
info = [[]] * 256; |
|
for line in lines: |
fields = line.split(',') |
opc = int(fields[0],16) |
info[opc] = (int(fields[1]), int(fields[2]), int(fields[3])) |
return info |
|
|
def read_opcode_info(filename): |
""" |
Read a table of MCS51 opcodes from a plain text file. |
Rather than writing here a lengthy explanation I invite you to see the |
opcode table text file "opcode_info.txt". |
Since the file is known, we don't provide for formatting errors, missing |
lines or any kind of trouble. |
This file has been copy-pasted straight from Keil's website and slightly |
edited. |
""" |
|
# Open file and read it into a list of lines. |
fin = open(filename, "r") |
lines = fin.readlines() |
fin.close() |
|
# We'll build a table with 256 entries, one per opcode. |
info = [[]] * 256; |
|
for line in lines: |
[opcode, _, line] = line.partition('\t') |
[nbytes, _, line] = line.partition('\t') |
[mnemonic, _, operands] = line.partition('\t') |
i = int(opcode, 16) |
info[i] = [mnemonic.strip(), operands.strip(), int(nbytes)] |
|
return info |
|
def opcode_unimplemented(opc): |
"""Return true if the opcode is not implemented (implemented as NOP).""" |
# FIXME this should be optional, like the implementation itself. |
return opc=="DA" or opc=="XCHD" |
|
|
def build_svg_table(info, cycles, part): |
""" |
Render the opcode table, or one half of it, in SVG format. |
@arg info Array of opcode information as returned by read_opcode_info. |
@arg cycles Array of opcode cycle counts as returned by read_cycle_info. |
@arg part Can be one of ("left","right","full"). |
Return a string in SVG format to be written to a file. |
""" |
|
|
# (lc,hc) is the range of columns we're going to draw. It can be the whole |
# table or the left or right half. |
if part=="left": |
lc = 0 |
hc = 8 |
elif part=="right": |
lc = 8 |
hc = 16 |
else: |
lc = 0 |
hc = 16 |
|
# Hardcode the rendering parameters: size of the cells, etc. |
# Note that other parameters (font size and text coordinates) are hardcoded |
# in the string literals below. |
scale = 1.0 |
c_width = 300 |
c_height = 200 |
cr_height = c_height |
cr_width = c_width / 2 |
cc_height = c_height / 2 |
cc_width = c_width |
|
# Compute the SVG frame size according to the selected part. |
w = hc - lc |
width = c_width*w + cr_width + 20 |
height = c_height*16 + cc_height + 20 |
|
# This is the SVG header template. |
header = \ |
"<svg xmlns='http://www.w3.org/2000/svg' \n" + \ |
"xmlns:xlink='http://www.w3.org/1999/xlink' \n" + \ |
"width='%d' height='%d' viewbox='0 0 %d %d' \n" + \ |
"preserveAspectRatio='none'>\n\n" |
|
# We'll append all the SVG text onto this variable. |
svg = "" |
|
# Build the SVG header with the selected size. |
svg = svg + header % (width, height, width, height) |
|
# SVG definitions template. There's 3 cells, for the table borders and |
# the table body. |
defs = \ |
'<defs>\n' + \ |
'<!-- Basic table cell -->\n' + \ |
'<rect height="%d" width="%d" stroke="black" stroke-width="1" id="s"/>\n' + \ |
'<!-- Row index cell -->\n' + \ |
'<rect height="%d" width="%d" stroke="black" stroke-width="1" id="r"/>\n' + \ |
'<!-- Col index cell -->\n' + \ |
'<rect height="%d" width="%d" stroke="black" stroke-width="1" id="c"/>\n' + \ |
'</defs>\n\n' |
|
# Build SVG definitions block with its parameters -- cell sizes. |
svg = svg + defs % (c_height, c_width, cr_height, cr_width, cc_height, cc_width) |
|
# This is a SVG group template for the main table cell. |
# Note that the font sizes and text coordinates are hardcoded! |
base_cell = \ |
'<g transform="translate(%d,%d) scale(%f)">\n' + \ |
'<use x="0" y="0" xlink:href="#s" fill="%s"/>\n' + \ |
'<text x="80" y="90" font-family="sans-serif" font-size="55">%s</text>\n' + \ |
'<text x="80" y="140" font-family="sans-serif" font-size="40">%s</text>\n' + \ |
'<text x="10" y="40" font-family="verdana" fill="red" font-size="40">%s</text>\n' + \ |
'<text x="260" y="40" font-family="verdana" fill="blue" font-size="40">%d</text>\n' + \ |
'</g>\n\n' |
|
# SCG group template for a cell to the left of the table with a row number. |
row_index_cell = \ |
'<g transform="translate(%d,%d) scale(%f)">\n' + \ |
'<use x="0" y="0" xlink:href="#r" fill="white"/>\n' + \ |
'<text x="80" y="90" font-family="sans-serif" font-size="55">%01X</text>\n' + \ |
'</g>\n\n' |
|
# SCG group template for a cell at the top of the table with a col number. |
col_index_cell = \ |
'<g transform="translate(%d,%d) scale(%f)">\n' + \ |
'<use x="0" y="0" xlink:href="#c" fill="white"/>\n' + \ |
'<text x="80" y="70" font-family="sans-serif" font-size="55">%01X</text>\n' + \ |
'</g>\n\n' |
|
# Build the top row of the table: cells with the column number. |
for col in range(lc,hc): |
y = 10 |
x = 10 + (cr_width + (col-lc)*c_width)*scale |
svg = svg + col_index_cell % (x, 10, scale, col) |
|
# Now, for each of the 16 rows... |
for row in range(16): |
# ...compute the row vertical coordinate... |
y = 10 + (cc_height + row*c_height)*scale |
# ...render the leftmost cell with the row index... |
svg = svg + row_index_cell % (10, y, scale, row) |
# ...and render the row of main-table-body cells. |
|
# for each of the cells in the column range we're rendering... |
for col in range(lc,hc): |
# ...compute the horizintal coordinate of the cell... |
x = 10 + (cr_width + (col-lc)*c_width)*scale |
|
# ...and extract the cycle count data from the array. |
opc = col*16 + row |
min = cycles[opc][0] |
max = cycles[opc][1] |
# When min/=max we need to display both values (conditional |
# jumps, for instance). |
# Those opcodes with a min value >=999 have not been executed by |
# the simulation and we'll render them in a darker shade of grey. |
if min < 999: |
if min==max: |
count = str(min) |
else: |
count = str(min) + "/" + str(max) |
color = "white" |
else: |
count = " " |
color = "#e0e0e0" |
|
# Render the cell with all its parameters. |
|
|
# Render the 'optional' opcodes in red. |
if opcode_unimplemented(info[opc][0]): |
color = "#f0b0b0" |
|
cell = base_cell % (x, y, scale, color, info[opc][0], info[opc][1], count, info[opc][2]) |
|
svg = svg + cell |
|
# Done, close the SVG element and we're done. |
svg = svg + '</svg>' |
|
return svg |
|
|
def write_cycle_table(cycle_info, c_table_file): |
""" |
Writes the cycle count info in the format of a C literal table. |
Meant to be copied and pasted into the B51 simulator. |
""" |
|
txt = "typedef struct {\n" |
txt = txt + " int min;\n" |
txt = txt + " int max;\n" |
txt = txt + "} cycle_count_t;\n" |
txt = txt + "\n\n" |
txt = txt + "cycle_count_t cycle_count[256] = {\n " |
for i in range(len(cycle_info)): |
item = cycle_info[i] |
if item[2] == 0: |
txt = txt + "{ 0, 0}, " |
else: |
txt = txt + "{%2u,%2u}, " % (item[0], item[1]) |
if (i % 8) == 7: |
txt = txt + "\n " |
txt = txt + "};\n\n" |
|
|
fout = open(c_table_file, "w") |
fout.write(txt) |
fout.close() |
|
|
def main(argv): |
"""Main body of the program.""" |
|
# We should parse the command line arguments, etc. |
# For this quick-and-dirty script we'll hardcode all the parameters... |
|
# ...the target svg file names... |
svg_base_filename = "./table" |
# ...the target text file name where a C-format table with the cycle counts |
# will be written to... |
c_table_file = "./cycle_table.c" |
# ...and the source CSV cycle count log file. Note this path is the default |
# working path for the Modelsim simulations, change if necessary. |
cycle_log_filename = "../../sim/cycle_count_log.csv" |
|
# Read cycle count data... |
cycle_info = read_cycle_info(cycle_log_filename) |
# ...and read opcode table data (instruction mnemonics and byte counts). |
opcode_info = read_opcode_info("opcode_info.txt") |
|
# First of all, write the C-format cycle table, to be copied and pasted |
# into the B51 simulator. |
write_cycle_table(cycle_info, c_table_file) |
|
# We can render the opcode table 'whole', resulting in a wide table, or |
# we can render the left and right halves separately, which gives a format |
# better suted for a printed page. |
|
# So, for all three possible rendering formats... |
parts = ("left", "right", "full") |
# ...render the opcode table. |
for part in parts: |
|
# Build the SVG text for the table... |
svg = build_svg_table(opcode_info, cycle_info, part) |
# ...and write it to the target file. |
fout = None |
try: |
full_filename = svg_base_filename + "_" + part + ".svg" |
fout = open(full_filename, "w") |
fout.write(svg) |
fout.close() |
print "SVG opcode table written to %s" % full_filename |
except: |
print "Trouble opening %s for output" % full_filename |
finally: |
if fout: fout.close() |
|
|
if __name__ == "__main__": |
main(sys.argv[1:]) |
sys.exit(0) |
|
|
/trunk/tools/b51/src/b51_cpu.c
0,0 → 1,1388
|
#include <stdint.h> |
#include <stdbool.h> |
#include <stdio.h> |
|
#include "b51_cpu.h" |
#include "b51_mcu.h" |
#include "b51_log.h" |
#include "util/ihex.h" |
|
|
/*-- Local data types & macros -----------------------------------------------*/ |
|
typedef enum cpu_op_e { |
add, addc, subb, |
alu_mul, alu_div, |
da, |
rrc, rlc, rr, rl, |
setb_c, clr_c, anl_c, orl_c, |
cjne |
} cpu_op_t; |
|
/** Cycle count information for an opcode. */ |
typedef struct { |
int min; /**< Minimum number of cycles. */ |
int max; /**< Maximum number of cycles. */ |
} cycle_count_t; |
|
/** Cycle count table for light52 core. */ |
cycle_count_t cycle_count[256] = { |
{ 2, 2}, { 5, 5}, { 6, 6}, { 3, 3}, { 3, 3}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 7, 8}, { 7, 7}, { 8, 8}, { 3, 3}, { 3, 3}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 6, 7}, { 5, 5}, { 7, 7}, { 3, 3}, { 4, 4}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 6, 7}, { 7, 7}, { 7, 7}, { 3, 3}, { 4, 4}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 3, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 4, 4}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 3, 5}, { 7, 7}, { 5, 5}, { 5, 5}, { 4, 4}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 3, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 4, 4}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 3, 5}, { 7, 7}, { 5, 5}, { 4, 4}, { 4, 4}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 4, 4}, { 4, 4}, { 4, 4}, { 4, 4}, { 4, 4}, { 4, 4}, { 4, 4}, { 4, 4}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 4, 4}, {10,10}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 5, 5}, { 7, 7}, { 5, 5}, { 4, 4}, { 4, 4}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 3, 3}, { 3, 3}, { 2, 2}, { 6, 6}, { 6, 6}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 5, 5}, { 7, 7}, { 5, 5}, { 3, 3}, { 5, 6}, { 6, 7}, { 8, 9}, { 8, 9}, |
{ 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 3, 3}, { 3, 3}, { 6, 6}, { 7, 7}, { 7, 7}, |
{ 6, 6}, { 6, 6}, { 6, 6}, { 6, 6}, { 6, 6}, { 6, 6}, { 6, 6}, { 6, 6}, |
{ 5, 5}, { 7, 7}, { 5, 5}, { 3, 3}, { 2, 2}, { 7, 8}, { 2, 2}, { 2, 2}, |
{ 7, 8}, { 7, 8}, { 7, 8}, { 7, 8}, { 7, 8}, { 7, 8}, { 7, 8}, { 7, 8}, |
{ 3, 3}, { 5, 5}, { 6, 6}, { 6, 6}, { 3, 3}, { 5, 5}, { 7, 7}, { 7, 7}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
{ 3, 3}, { 7, 7}, { 5, 5}, { 5, 5}, { 3, 3}, { 4, 4}, { 5, 5}, { 5, 5}, |
{ 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, { 5, 5}, |
}; |
|
|
|
|
/*-- Local function prototypes -----------------------------------------------*/ |
|
|
static uint8_t cpu_fetch(cpu51_t *cpu); |
static uint16_t cpu_fetch16(cpu51_t *cpu); |
static uint16_t cpu_fetch11(cpu51_t *cpu, uint8_t opcode); |
static uint8_t cpu_xcode_read(cpu51_t *cpu, uint16_t addr); |
static uint8_t cpu_xdata_read(cpu51_t *cpu, uint16_t addr); |
static void cpu_xdata_write(cpu51_t *cpu, uint16_t addr, uint8_t value); |
static void cpu_set_rn(cpu51_t *cpu, uint8_t n, uint8_t value); |
static void cpu_set_a(cpu51_t *cpu, uint8_t value); |
static uint8_t cpu_update_flags(cpu51_t *cpu, uint8_t x, uint8_t y, cpu_op_t op); |
static uint8_t cpu_compute_ac(cpu51_t *cpu, uint8_t x, uint8_t y, cpu_op_t op); |
static void cpu_set_dir(cpu51_t *cpu, uint8_t dir, uint8_t value); |
static void cpu_set_idata(cpu51_t *cpu, uint8_t dir, uint8_t value); |
static uint8_t cpu_get_dir(cpu51_t *cpu, uint8_t dir); |
static uint8_t cpu_get_idata(cpu51_t *cpu, uint8_t dir); |
static bool cpu_rel_jump(cpu51_t *cpu, uint8_t rel); |
static void cpu_set_sfr(cpu51_t *cpu, uint8_t dir, uint8_t value); |
static uint8_t cpu_get_sfr(cpu51_t *cpu, uint8_t dir); |
static uint8_t cpu_get_bit_address(cpu51_t *cpu, uint8_t bit); |
static uint8_t cpu_get_bit(cpu51_t *cpu, uint8_t bit); |
static void cpu_set_bit(cpu51_t *cpu, uint8_t bit, uint8_t value); |
|
static bool cpu_exec_rn(cpu51_t *cpu, uint8_t opcode); |
static bool cpu_exec_upper_half(cpu51_t *cpu, uint8_t opcode); |
|
|
/*-- Public functions --------------------------------------------------------*/ |
|
extern uint16_t cpu_load_code(cpu51_t *cpu, const char *hex_filename){ |
FILE *fp; |
IHexRecord irec; |
uint16_t i, target, bytes_read=0; |
|
fp = fopen(hex_filename, "r"); |
if (fp == NULL) { |
perror("Error opening file"); |
return 0; |
} |
|
while (Read_IHexRecord(&irec, fp) == IHEX_OK) { |
/* Debug: print read record */ |
#if 0 |
Print_IHexRecord(&irec); |
printf("\n"); |
#endif |
/* Move data from record to XCODE space, no questions asked */ |
/* FIXME XCODE size hardcoded here */ |
target = irec.address; |
for(i=0; i < irec.dataLen && (target+i)<65536; i++){ |
cpu->mcu.xcode[target + i] = irec.data[i]; |
} |
bytes_read += irec.dataLen; |
} |
|
fclose(fp); |
|
if(bytes_read > 0){ |
printf("Read %d code bytes from '%s'\n", bytes_read, hex_filename); |
} |
|
return bytes_read; |
} |
|
extern void cpu_init(cpu51_t *cpu){ |
/* Not much to init in the CPU so far */ |
cpu->breakpoint = 0xffff; /* FIXME implementation of BP is flimsy */ |
cpu->log.executed_instructions = 0; |
/* Set the core implementation options to their default value */ |
cpu->options.bcd = false; |
/* now init the MCU model -- peripherals */ |
mcu_init(&cpu->mcu); |
} |
|
extern void cpu_reset(cpu51_t *cpu){ |
/* Give CPU registers their reset value, if any */ |
cpu->sfr.dph = 0x00; |
cpu->sfr.dpl = 0x00; |
cpu->sfr.sp = 0x07; |
cpu->sfr.psw = 0x00; |
cpu->pc = 0x0000; |
cpu->cycles = 0; |
/* FIXME reset interrupt level */ |
/* Now reset the MCU model -- peripherals */ |
mcu_reset(&cpu->mcu); |
} |
|
extern bool cpu_add_breakpoint(cpu51_t *cpu, uint16_t address){ |
cpu->breakpoint = address; |
return true; |
} |
|
extern uint32_t cpu_exec(cpu51_t *cpu, uint32_t num_inst){ |
uint8_t opcode; |
uint32_t i; |
bool ok; |
uint32_t cycles; |
|
for(i=0;i<num_inst;i++){ |
log_baseline(&(cpu->log), cpu->pc, cpu->sfr.sp, cpu->a, cpu->sfr.psw); |
|
if(cpu->pc == cpu->breakpoint){ |
printf("BREAKPOINT hit at %04Xh\n", cpu->breakpoint); |
return 2; |
} |
|
opcode = cpu_fetch(cpu); |
cpu->max_cycle_count = false; |
cpu->implemented_as_nop = false; |
|
if((opcode & 0x08)!=0){ |
/* bottom half of decoding table */ |
ok = cpu_exec_rn(cpu, opcode); |
} |
else{ |
/* top half of decoding table */ |
ok = cpu_exec_upper_half(cpu, opcode); |
} |
|
/* Update cycle counter... */ |
if(cpu->implemented_as_nop){ |
/* Instruction is not implemented as per command line parameters; |
it was executed as NOP so its cycle count is that of NOP.*/ |
cycles = cycle_count[0].min; |
} |
else{ |
if(cpu->max_cycle_count){ |
cycles = cycle_count[opcode].max; |
} |
else{ |
cycles = cycle_count[opcode].min; |
} |
} |
cpu->cycles += cycles; |
|
mcu_update(&cpu->mcu, cycles); |
log_status(&(cpu->log), cpu->sfr.sp, cpu->a, cpu->sfr.psw); |
|
cpu->log.executed_instructions++; |
|
/* Break execution on any kind of trouble */ |
/* FIXME handle execution faults */ |
if(!ok) { |
return 1; |
break; |
} |
} |
|
return 0; |
} |
|
/*-- Local functions ---------------------------------------------------------*/ |
|
/** |
Get the byte pointed to by PC, increment PC. |
|
This function and cpu_xcode_read encapsulate code space addressing. |
|
@arg CPU object. |
@return Opcode at PC. |
@sideeffect CPU state updated accordingly. |
*/ |
static uint8_t cpu_fetch(cpu51_t *cpu){ |
return cpu_xcode_read(cpu, cpu->pc++); |
} |
|
static uint16_t cpu_fetch16(cpu51_t *cpu){ |
uint8_t hi, lo; |
uint16_t word; |
|
hi = cpu_fetch(cpu); |
lo = cpu_fetch(cpu); |
word = ((uint16_t)hi << 8) + (uint16_t)lo; |
return word; |
} |
|
static uint16_t cpu_fetch11(cpu51_t *cpu, uint8_t opcode){ |
uint8_t hi, lo, tmp; |
uint16_t word; |
|
lo = cpu_fetch(cpu); |
hi = (opcode >> 5) & 0x07; |
tmp = (cpu->pc >> 8) & 0xf8; |
hi |= tmp; |
word = ((uint16_t)hi << 8) + (uint16_t)lo; |
return word; |
} |
|
|
static uint8_t cpu_xcode_read(cpu51_t *cpu, uint16_t addr){ |
return cpu->mcu.xcode[addr]; |
} |
|
|
static uint8_t cpu_xdata_read(cpu51_t *cpu, uint16_t addr){ |
return cpu->mcu.xdata[addr]; |
} |
|
static void cpu_xdata_write(cpu51_t *cpu, uint16_t addr, uint8_t value){ |
/*if(cpu->mcu.xdata[addr]!=value){*/ |
log_xdata(&(cpu->log), addr, value); |
/*}*/ |
cpu->mcu.xdata[addr] = value; |
} |
|
|
static uint8_t cpu_get_rn(cpu51_t *cpu, uint8_t n){ |
uint8_t idata_address; |
|
idata_address = (cpu->sfr.psw & 0x18) + (n & 0x07); |
return cpu->idata[idata_address]; |
} |
|
static void cpu_set_rn(cpu51_t *cpu, uint8_t n, uint8_t value){ |
uint8_t idata_address; |
|
idata_address = (cpu->sfr.psw & 0x18) + (n & 0x07); |
cpu_set_idata(cpu, idata_address, value); |
} |
|
static void cpu_set_a(cpu51_t *cpu, uint8_t value){ |
uint8_t p, t, i; |
|
cpu->a = value; |
|
/* Update P flag */ |
t = cpu->a; |
p = 0; |
for(i=0;i<8;i++){ |
p = p ^ (t & 0x01); |
t = t >> 1; |
} |
cpu->sfr.psw &= 0x0fe; |
cpu->sfr.psw |= (p & 0x01); |
} |
|
|
static uint8_t set_bit(uint8_t target, uint8_t index, uint8_t value){ |
index &= 0x07; |
target &= ~(1 << index); |
value &= 0x01; |
target |= (value << index); |
return target; |
} |
|
static uint8_t cpu_compute_ac(cpu51_t *cpu, uint8_t x, uint8_t y, cpu_op_t op){ |
|
if(op==subb){ |
x = x & 0x0f; |
y = y & 0x0f; |
if((cpu->sfr.psw)&0x80){ |
y++; |
} |
return (x<y)?1:0; |
} |
else{ |
x = x & 0x0f; |
y = y & 0x0f; |
if((cpu->sfr.psw)&0x80){ |
y++; |
} |
return ((x+y)>0x0f)?1:0; |
} |
} |
|
static uint8_t cpu_update_flags(cpu51_t *cpu, uint8_t s, uint8_t d, cpu_op_t op){ |
uint16_t res, x, y, res_half, rem; |
uint16_t cy=0, ov=0, ac=0; |
|
x = (uint16_t)s; |
y = (uint16_t)d; |
|
switch(op){ |
case add: |
res = x + y; |
res_half = (x & 0x0f) + (y & 0x0f); |
cy = (res & 0x0100)? 1 : 0; |
ac = (res_half & 0x0010)? 1 : 0; |
if((x < 0x80) && (y < 0x80)){ |
ov = (res & 0x0080)? 1 : 0; |
} |
else if((x >= 0x80) && (y >= 0x80)){ |
ov = (~(res & 0x0080))? 1 : 0; |
} |
else{ |
ov = 0; |
} |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, cy); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 6, ac); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 2, ov); |
break; |
case subb: |
ac = cpu_compute_ac(cpu, x, y, subb); |
y ^= 0xffff; |
y += 1; |
res = x + y; |
if(cpu->sfr.psw & 0x80){ |
res--; |
} |
cy = (res & 0x0100)? 1 : 0; |
|
if((x < 0x80) && (y >= 0x80)){ |
/* positive - negative = positive, otherwise OV */ |
ov = (res & 0x0080)? 1 : 0; |
} |
else if((x >= 0x80) && (y < 0x80)){ |
/* negative - positive = negative, otherwise OV */ |
ov = (~(res & 0x0080))? 1 : 0; |
} |
else{ |
ov = 0; |
} |
|
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, cy); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 6, ac); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 2, ov); |
break; |
case addc: |
res = x + y; |
res_half = (x & 0x0f) + (y & 0x0f); |
if(cpu->sfr.psw & 0x80){ |
res++; |
res_half++; |
} |
cy = (res & 0x0100)? 1 : 0; |
ac = (res_half & 0x0010)? 1 : 0; |
if((x < 0x80) && (y < 0x80)){ |
ov = (res & 0x0080)? 1 : 0; |
} |
else if((x >= 0x80) && (y >= 0x80)){ |
ov = (~(res & 0x0080))? 1 : 0; |
} |
else{ |
ov = 0; |
} |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, cy); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 6, ac); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 2, ov); |
break; |
case alu_mul: |
res = x * y; |
ov = (res & 0xff00)? 1 : 0; |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, 0); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 2, ov); |
/* special case: update B right here */ |
cpu->sfr.b = (res>>8)&0xff; |
res = res & 0xff; |
break; |
case alu_div: |
if(y != 0){ |
res = x / y; |
rem = x % y; |
cy = 0; |
ov = 0; |
/* special case: update B right here */ |
cpu->sfr.b = rem; |
} |
else{ |
ov = 1; |
cy = 0; |
/* Quotient and remainder are undefined in Intel specs; we'll use |
light52 actual values for consistency of the SW/HW simulations */ |
res = 0xff; |
rem = 0x00; |
} |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, cy); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 2, ov); |
break; |
case da: |
x = s & 0x0f; |
y = s; |
if((x > 9) || ((cpu->sfr.psw&0x40)!=0)){ |
y += 0x06; |
} |
x = (y >> 4) & 0x1f; |
if((x > 9) || ((cpu->sfr.psw&0x80)!=0)){ |
y += 0x60; |
} |
res = y & 0x0ff; |
/* DA can SET C but can't clear it if it's set */ |
if(y > 0x0ff){ |
cpu->sfr.psw |= 0x80; |
} |
break; |
case rlc: |
res = (s << 1) | (cpu->sfr.psw >> 7); |
cy = (s >> 7) & 0x01; |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, cy); |
break; |
case rl: |
res = (s << 1) | ((s >> 7) & 0x01); |
break; |
case rrc: |
cy = (s & 0x01)? 1 : 0; |
res = ((s >> 1) & 0x7f) | (cpu->sfr.psw & 0x80); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, cy); |
break; |
case rr: |
res = ((s >> 1) & 0x7f) | ((s << 7) & 0x80); |
break; |
case setb_c: |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, 1); |
res = 0; /* unused ret value */ |
break; |
case clr_c: |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, 0); |
res = 0; /* unused ret value */ |
break; |
case anl_c: |
s = (cpu->sfr.psw >> 7); |
cy = s & d; |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, cy); |
break; |
case orl_c: |
s = (cpu->sfr.psw >> 7); |
cy = s | d; |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, cy); |
break; |
case cjne: |
if(x < y){ |
cpu->sfr.psw |= 0x80; |
} |
else{ |
cpu->sfr.psw &= ~0x80; |
} |
res = 0; |
break; |
} |
|
return res; |
} |
|
static void cpu_set_sfr(cpu51_t *cpu, uint8_t dir, uint8_t value){ |
uint16_t undefined_sfr=0; |
|
if(dir < 0x80) return; |
|
switch(dir){ |
case 0xe0: /* ACC */ |
cpu_set_a(cpu, value); |
break; |
case 0xf0: /* B */ |
cpu->sfr.b = value; |
break; |
case 0x83: /* DPH */ |
cpu->sfr.dph = value; |
break; |
case 0x82: /* DPL */ |
cpu->sfr.dpl = value; |
break; |
case 0xa8: /* IE */ |
cpu->sfr.ie = value; |
break; |
case 0xb8: /* IP */ |
cpu->sfr.ip = value; |
break; |
case 0x0d0: /* PSW */ |
/* The P flag can't be overwritten */ |
cpu->sfr.psw = (value & 0xfe) | (cpu->sfr.psw & 0x01); |
break; |
case 0x081: /* SP */ |
cpu->sfr.sp = value; |
break; |
default: |
undefined_sfr = mcu_set_sfr(&cpu->mcu, dir, value); |
if(undefined_sfr){ |
/* TODO unimplemented SFR addr message should be optional */ |
printf("(%04X) UNIMPLEMENTED SFR %02X\n", cpu->log.pc, dir); |
} |
} |
log_sfr(&(cpu->log), dir, value); |
} |
|
static uint8_t cpu_get_sfr(cpu51_t *cpu, uint8_t dir){ |
uint16_t sfr_value; |
|
/* TODO this is a bug and some fault flag should be raised */ |
if(dir < 0x80) return 0; |
|
switch(dir){ |
case 0xe0: /* ACC */ |
return cpu->a; |
break; |
case 0xf0: /* B */ |
return cpu->sfr.b; |
break; |
case 0x83: /* DPH */ |
return cpu->sfr.dph; |
break; |
case 0x82: /* DPL */ |
return cpu->sfr.dpl; |
break; |
case 0xa8: /* IE */ |
return cpu->sfr.ie; |
break; |
case 0xb8: /* IP */ |
return cpu->sfr.ip; |
break; |
case 0x0d0: /* PSW */ |
return cpu->sfr.psw; |
break; |
case 0x081: /* SP */ |
return cpu->sfr.sp; |
break; |
default: |
sfr_value = mcu_get_sfr(&cpu->mcu, dir); |
if(sfr_value==0xffff){ |
/* TODO unimplemented SFR addr message should be optional */ |
printf("(%04X) UNIMPLEMENTED SFR %02X\n", cpu->log.pc, dir); |
} |
else{ |
return (uint8_t)sfr_value; |
} |
} |
|
/* Control will never actually reach here */ |
return 0; |
} |
|
static void cpu_set_idata(cpu51_t *cpu, uint8_t dir, uint8_t value){ |
/* FIXME check bounds */ |
cpu->idata[dir] = value; |
log_idata(&(cpu->log), dir, value); |
} |
|
static void cpu_set_dir(cpu51_t *cpu, uint8_t dir, uint8_t value){ |
/* Direct addressing mode is special; can access both idata and sfr */ |
if(dir > 0x07f){ |
/* In direct addressing mode, 0x80 to 0xff is actually an SFR address */ |
cpu_set_sfr(cpu, dir, value); |
} |
else{ |
/* From 0x00 to 0x7f, we're addressing regular idata RAM */ |
cpu->idata[dir] = value; |
log_idata(&(cpu->log), dir, value); |
} |
} |
|
static uint8_t cpu_get_dir(cpu51_t *cpu, uint8_t dir){ |
/* Direct addressing mode is special; can access both idata and sfr */ |
if(dir > 0x07f){ |
/* In direct addressing mode, 0x80 to 0xff is actually an SFR address */ |
return cpu_get_sfr(cpu, dir); |
} |
else{ |
/* From 0x00 to 0x7f, we're addressing regular idata RAM */ |
return cpu->idata[dir]; |
} |
} |
|
static uint8_t cpu_get_idata(cpu51_t *cpu, uint8_t dir){ |
/* FIXME check bounds */ |
return cpu->idata[dir]; |
} |
|
|
static bool cpu_rel_jump(cpu51_t *cpu, uint8_t rel){ |
int16_t target, offset; |
|
target = (int16_t)cpu->pc; |
offset = (int16_t)((int8_t)rel); |
target += offset; |
cpu->pc = (uint16_t)target; |
return log_jump(&(cpu->log), cpu->pc); |
} |
|
|
static uint8_t cpu_get_bit_address(cpu51_t *cpu, uint8_t bit){ |
uint8_t addr; |
|
if(bit > 0x7f){ |
addr = bit & 0xf8; |
} |
else{ |
addr = 0x20 + (bit >> 3); |
} |
|
return addr; |
} |
|
|
static uint8_t cpu_get_bit(cpu51_t *cpu, uint8_t bit){ |
uint8_t dir, res, value; |
|
dir = cpu_get_bit_address(cpu, bit); |
res = cpu_get_dir(cpu, dir); |
value = (res & (1 << (bit & 0x07)))? 1 : 0; |
|
return value; |
} |
|
|
static void cpu_set_bit(cpu51_t *cpu, uint8_t bit, uint8_t value){ |
uint8_t dir, res; |
|
dir = cpu_get_bit_address(cpu, bit); |
res = cpu_get_dir(cpu, dir); |
res = set_bit(res, bit, value); |
cpu_set_dir(cpu, dir, res); |
} |
|
|
static bool cpu_exec_upper_half(cpu51_t *cpu, uint8_t opcode){ |
uint8_t imm, dir, dir2, bit, res, rel, val; |
uint8_t hi, lo; |
uint16_t address; |
bool ok = true, endless_loop = false; |
|
|
switch(opcode){ |
/*-- ROW 0 ---------------------------------------------------------------*/ |
case 0x00: /* NOP */ |
break; |
case 0x10: /* Jcc bit, rel */ |
case 0x20: |
case 0x30: |
bit = cpu_fetch(cpu); |
rel = cpu_fetch(cpu); |
dir = cpu_get_bit_address(cpu, bit); |
res = cpu_get_dir(cpu, dir); |
switch(opcode){ |
case 0x10: /* JBC bit, rel */ |
val = res & (1 << (bit & 0x07)); |
res &= ~(1 << (bit & 0x07)); |
cpu_set_dir(cpu, dir, res); |
if(val){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0x20: /* JB bit, rel */ |
if(res & (1 << (bit & 0x07))){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0x30: /* JC bit, rel */ |
if((res & (1 << (bit & 0x07))) ==0){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
} |
break; |
case 0x40: /* JC rel */ |
rel = cpu_fetch(cpu); |
if(cpu->sfr.psw & 0x80){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0x50: /* JNC rel */ |
rel = cpu_fetch(cpu); |
if(!(cpu->sfr.psw & 0x80)){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0x60: /* JZ rel */ |
rel = cpu_fetch(cpu); |
if(cpu->a == 0){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0x70: /* JNZ rel */ |
rel = cpu_fetch(cpu); |
if(cpu->a != 0){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0x80: /* SJMP rel */ |
rel = cpu_fetch(cpu); |
endless_loop = cpu_rel_jump(cpu, rel); |
break; |
case 0x90: /* MOV DPTR, #addr16 */ |
hi = cpu_fetch(cpu); |
lo = cpu_fetch(cpu); |
cpu->sfr.dph = hi; |
cpu->sfr.dpl = lo; |
log_sfr(&(cpu->log), 0x83, hi); |
log_sfr(&(cpu->log), 0x82, lo); |
break; |
case 0xa0: /* ORL C, /bit */ |
bit = cpu_fetch(cpu); |
res = 1 - cpu_get_bit(cpu, bit); |
cpu->sfr.psw |= (res << 7); |
break; |
case 0xb0: /* ANL C, /bit */ |
bit = cpu_fetch(cpu); |
res = 1 - cpu_get_bit(cpu, bit); |
cpu->sfr.psw &= (res << 7); |
break; |
case 0xc0: /* PUSH dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
cpu->sfr.sp++; |
cpu_set_idata(cpu, cpu->sfr.sp, res); |
break; |
case 0xd0: /* POP dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_idata(cpu, cpu->sfr.sp--); |
cpu_set_dir(cpu, dir, res); |
break; |
case 0xe0: /* MOVX A, @DPTR */ |
address = (((uint16_t)cpu->sfr.dph) << 8) + (uint16_t)cpu->sfr.dpl; |
res = cpu_xdata_read(cpu, address); |
cpu_set_a(cpu, res); |
break; |
case 0xf0: /* MOVX @DPTR, A */ |
address = (((uint16_t)cpu->sfr.dph) << 8) + (uint16_t)cpu->sfr.dpl; |
cpu_xdata_write(cpu, address, cpu->a); |
break; |
/*-- ROW 1 ---------------------------------------------------------------*/ |
case 0x01: case 0x21: case 0x41: case 0x61: /* AJMP addr11 */ |
case 0x81: case 0xa1: case 0xc1: case 0xe1: |
address = cpu_fetch11(cpu, opcode); |
cpu->pc = address; |
endless_loop = log_jump(&(cpu->log), address); |
break; |
case 0x11: case 0x31: case 0x51: case 0x71: /* ACALL addr11 */ |
case 0x91: case 0xb1: case 0xd1: case 0xf1: |
address = cpu_fetch11(cpu, opcode); |
hi = (uint8_t)(cpu->pc >> 8); |
lo = (uint8_t)(cpu->pc >> 0); |
cpu->sfr.sp++; |
cpu_set_idata(cpu, cpu->sfr.sp, lo); |
cpu->sfr.sp++; |
cpu_set_idata(cpu, cpu->sfr.sp, hi); |
cpu->pc = address; |
endless_loop = log_jump(&(cpu->log), address); |
break; |
/*-- ROW 2 ---------------------------------------------------------------*/ |
case 0x02: /* LJMP addr16 */ |
address = cpu_fetch16(cpu); |
cpu->pc = address; |
endless_loop = log_jump(&(cpu->log), address); |
break; |
case 0x12: /* LCALL addr16 */ |
address = cpu_fetch16(cpu); |
hi = (uint8_t)(cpu->pc >> 8); |
lo = (uint8_t)(cpu->pc >> 0); |
cpu->sfr.sp++; |
cpu_set_idata(cpu, cpu->sfr.sp, lo); |
cpu->sfr.sp++; |
cpu_set_idata(cpu, cpu->sfr.sp, hi); |
cpu->pc = address; |
endless_loop = log_jump(&(cpu->log), address); |
break; |
case 0x22: /* RET */ |
hi = cpu_get_idata(cpu, cpu->sfr.sp--); |
lo = cpu_get_idata(cpu, cpu->sfr.sp--); |
address = ((uint16_t)hi << 8) + (uint16_t)lo; |
cpu->pc = address; |
endless_loop = log_jump(&(cpu->log), address); |
break; |
case 0x32: /* RET */ |
/* FIXME interrupts unimplemented / RETI */ |
hi = cpu_get_idata(cpu, cpu->sfr.sp--); |
lo = cpu_get_idata(cpu, cpu->sfr.sp--); |
address = ((uint16_t)hi << 8) + (uint16_t)lo; |
cpu->pc = address; |
endless_loop = log_jump(&(cpu->log), address); |
break; |
case 0x42: /* ORL dir, A */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res | cpu->a; |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x52: /* ANL dir, A */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res & cpu->a; |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x62: /* XRL dir, A */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res ^ cpu->a; |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x72: /* ORL C, bit */ |
bit = cpu_fetch(cpu); |
res = cpu_get_bit(cpu, bit); |
cpu->sfr.psw |= (res << 7); |
break; |
case 0x82: /* ANL C, bit */ |
bit = cpu_fetch(cpu); |
res = cpu_get_bit(cpu, bit); |
cpu->sfr.psw &= (res << 7); |
break; |
case 0x92: /* MOV bit, C */ |
bit = cpu_fetch(cpu); |
cpu_set_bit(cpu, bit, (cpu->sfr.psw >> 7)); |
break; |
case 0xa2: /* MOV C, bit */ |
bit = cpu_fetch(cpu); |
res = cpu_get_bit(cpu, bit); |
cpu->sfr.psw = set_bit(cpu->sfr.psw, 7, res); |
break; |
case 0xb2: /* CPL bit */ |
bit = cpu_fetch(cpu); |
dir = cpu_get_bit_address(cpu, bit); |
res = cpu_get_dir(cpu, dir); |
res ^= (1 << (bit & 0x07)); |
cpu_set_dir(cpu, dir, res); |
break; |
case 0xc2: /* CLR bit */ |
bit = cpu_fetch(cpu); |
dir = cpu_get_bit_address(cpu, bit); |
res = cpu_get_dir(cpu, dir); |
res &= ~(1 << (bit & 0x07)); |
cpu_set_dir(cpu, dir, res); |
break; |
case 0xd2: /* SETB bit */ |
bit = cpu_fetch(cpu); |
dir = cpu_get_bit_address(cpu, bit); |
res = cpu_get_dir(cpu, dir); |
res |= (1 << (bit & 0x07)); |
cpu_set_dir(cpu, dir, res); |
break; |
case 0xe2: /* MOVX A, @R0 */ |
/* TODO MOVX @Ri upper address byte hardcoded to zero */ |
address = ((uint16_t)cpu_get_rn(cpu, 0)) & 0x00ff; |
res = cpu_xdata_read(cpu, address); |
cpu_set_a(cpu, res); |
break; |
case 0xf2: /* MOVX @R0, A */ |
/* TODO MOVX @Ri upper address byte hardcoded to zero */ |
address = ((uint16_t)cpu_get_rn(cpu, 0)) & 0x00ff; |
cpu_xdata_write(cpu, address, cpu->a); |
break; |
/*-- ROW 3 ---------------------------------------------------------------*/ |
case 0x03: /* RR A */ |
val = cpu_update_flags(cpu, cpu->a, 0, rr); |
cpu_set_a(cpu, val); |
break; |
case 0x13: /* RRC A */ |
val = cpu_update_flags(cpu, cpu->a, 0, rrc); |
cpu_set_a(cpu, val); |
break; |
case 0x23: /* RL A */ |
val = cpu_update_flags(cpu, cpu->a, 0, rl); |
cpu_set_a(cpu, val); |
break; |
case 0x33: /* RLC A */ |
val = cpu_update_flags(cpu, cpu->a, 0, rlc); |
cpu_set_a(cpu, val); |
break; |
case 0x43: /* ORL dir, #data */ |
dir = cpu_fetch(cpu); |
imm = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res | imm; |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x53: /* ANL dir, #data */ |
dir = cpu_fetch(cpu); |
imm = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res & imm; |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x63: /* XRL dir, #data */ |
dir = cpu_fetch(cpu); |
imm = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res ^ imm; |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x73: /* JMP @A + DPTR */ |
address = (((uint16_t)cpu->sfr.dph) << 8) + (uint16_t)cpu->sfr.dpl; |
address += (uint16_t)(cpu->a); |
cpu->pc = address; |
endless_loop = log_jump(&(cpu->log), address); |
break; |
case 0x83: /* MOVC A, @A + PC */ |
/* Base is PC of NEXT instruction == cpu->pc */ |
address = cpu->pc + (uint16_t)(cpu->a); |
res = cpu_xcode_read(cpu, address); |
cpu_set_a(cpu, res); |
break; |
case 0x93: /* MOVC A, @A + DPTR */ |
address = (((uint16_t)cpu->sfr.dph) << 8) + (uint16_t)cpu->sfr.dpl; |
address += (uint16_t)(cpu->a); |
res = cpu_xcode_read(cpu, address); |
cpu_set_a(cpu, res); |
break; |
case 0xa3: /* INC DPTR */ |
address = (((uint16_t)cpu->sfr.dph) << 8) + (uint16_t)cpu->sfr.dpl; |
address++; |
cpu->sfr.dph = (uint8_t)(address >> 8); |
cpu->sfr.dpl = (uint8_t)(address >> 0); |
log_reg16(&(cpu->log), "DPTR", address); |
break; |
case 0xb3: /* CPL C */ |
cpu->sfr.psw ^= 0x80; |
break; |
case 0xc3: /* CLR C */ |
cpu->sfr.psw &= ~0x80; |
break; |
case 0xd3: /* SETB C */ |
cpu->sfr.psw |= 0x80; |
break; |
case 0xe3: /* MOVX A, @R0 */ |
/* TODO MOVX @Ri upper address byte hardcoded to zero */ |
address = ((uint16_t)cpu_get_rn(cpu, 1)) & 0x00ff; |
res = cpu_xdata_read(cpu, address); |
cpu_set_a(cpu, res); |
break; |
case 0xf3: /* MOVX @R0, A */ |
/* TODO MOVX @Ri upper address byte hardcoded to zero */ |
address = ((uint16_t)cpu_get_rn(cpu, 1)) & 0x00ff; |
cpu_xdata_write(cpu, address, cpu->a); |
break; |
/*-- ROW 4 ---------------------------------------------------------------*/ |
case 0x04: /* INC a */ |
cpu_set_a(cpu, cpu->a + 1); |
break; |
case 0x14: /* DEC a */ |
cpu_set_a(cpu, cpu->a - 1); |
break; |
case 0x24: /* ADD A, #imm */ |
imm = cpu_fetch(cpu); |
res = cpu_update_flags(cpu, cpu->a, imm, add); |
cpu_set_a(cpu, res); |
break; |
case 0x34: /* ADDC A, #imm */ |
imm = cpu_fetch(cpu); |
res = cpu_update_flags(cpu, cpu->a, imm, addc); |
cpu_set_a(cpu, res); |
break; |
case 0x44: /* ORL A, #imm */ |
imm = cpu_fetch(cpu); |
res = cpu->a | imm; |
cpu_set_a(cpu, res); |
break; |
case 0x54: /* ANL A, #imm */ |
imm = cpu_fetch(cpu); |
res = cpu->a & imm; |
cpu_set_a(cpu, res); |
break; |
case 0x64: /* XRL A, #imm */ |
imm = cpu_fetch(cpu); |
res = cpu->a ^ imm; |
cpu_set_a(cpu, res); |
break; |
case 0x74: /* MOV A, #data */ |
imm = cpu_fetch(cpu); |
cpu_set_a(cpu, imm); |
break; |
case 0x84: /* DIV AB */ |
res = cpu_update_flags(cpu, cpu->a, cpu->sfr.b, alu_div); |
cpu_set_a(cpu, res); |
break; |
case 0x94: /* SUBB A, #data */ |
imm = cpu_fetch(cpu); |
res = cpu_update_flags(cpu, cpu->a, imm, subb); |
cpu_set_a(cpu, res); |
break; |
case 0xa4: /* MUL AB */ |
res = cpu_update_flags(cpu, cpu->a, cpu->sfr.b, alu_mul); |
cpu_set_a(cpu, res); |
break; |
case 0xb4: /* CJNE A, #data, rel */ |
imm = cpu_fetch(cpu); |
rel = cpu_fetch(cpu); |
cpu_update_flags(cpu, cpu->a, imm, cjne); |
if(imm != cpu->a){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0xc4: /* SWAP A */ |
res = (cpu->a >> 4) & 0x0f; |
res = res | ((cpu->a << 4) & 0x0f0); |
cpu_set_a(cpu, res); |
break; |
case 0xd4: /* DA A */ |
if(cpu->options.bcd){ |
val = cpu_update_flags(cpu, cpu->a, 0, da); |
cpu_set_a(cpu, val); |
} |
else{ |
/* DA unimplemented, execute as NOP */ |
cpu->implemented_as_nop = true; |
} |
break; |
case 0xe4: /* CLR A */ |
cpu_set_a(cpu, 0); |
break; |
case 0xf4: /* CPL A */ |
cpu_set_a(cpu, ~(cpu->a)); |
break; |
/*-- ROW 5 ---------------------------------------------------------------*/ |
case 0x05: /* INC dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res + 1; |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x15: /* DEC dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res - 1; |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x25: /* ADD A, dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = cpu_update_flags(cpu, cpu->a, res, add); |
cpu_set_a(cpu, res); |
break; |
case 0x35: /* ADDC A, dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = cpu_update_flags(cpu, cpu->a, res, addc); |
cpu_set_a(cpu, res); |
break; |
case 0x45: /* ORL A, dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res | cpu->a; |
cpu_set_a(cpu, res); |
break; |
case 0x55: /* ANL A, dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res & cpu->a; |
cpu_set_a(cpu, res); |
break; |
case 0x65: /* XRL A, dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res ^ cpu->a; |
cpu_set_a(cpu, res); |
break; |
case 0x75: /* MOV dir, #imm */ |
dir = cpu_fetch(cpu); |
imm = cpu_fetch(cpu); |
cpu_set_dir(cpu, dir, imm); |
break; |
case 0x85: /* MOV dir1, dir2 */ |
dir = cpu_fetch(cpu); |
dir2 = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
cpu_set_dir(cpu, dir2, res); |
break; |
case 0x95: /* SUBB A, dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = cpu_update_flags(cpu, cpu->a, res, subb); |
cpu_set_a(cpu, res); |
break; |
case 0xa5: /* RESERVED A5h opcode : implemented as NOP */ |
cpu->implemented_as_nop = true; |
break; |
case 0xb5: /* CJNE A, dir, rel */ |
dir = cpu_fetch(cpu); |
rel = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
cpu_update_flags(cpu, cpu->a, res, cjne); |
if(res != cpu->a){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0xc5: /* XCH A,dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
cpu_set_dir(cpu, dir, cpu->a); |
cpu_set_a(cpu, res); |
break; |
case 0xd5: /* DJNZ dir, rel */ |
dir = cpu_fetch(cpu); |
rel = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
res = res - 1; |
cpu_set_dir(cpu, dir, res); |
if(res != 0){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0xe5: /* MOV a, dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
cpu_set_a(cpu, res); |
break; |
case 0xf5: /* MOV dir, a */ |
dir = cpu_fetch(cpu); |
cpu_set_dir(cpu, dir, cpu->a); |
break; |
/*-- ROW 6 & ROW 7 -------------------------------------------------------*/ |
/* IMPORTANT: |
All the cases in the x6 & x7 groups are PAIRED. The 'case fallthrough' |
is intentional. |
TODO label fallthrough case for lint tool. |
*/ |
case 0x06: /* INC @Ri */ |
case 0x07: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
cpu_set_idata(cpu, dir, res + 1); |
break; |
case 0x16: /* DEC @Ri */ |
case 0x17: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
cpu_set_idata(cpu, dir, res - 1); |
break; |
case 0x26: /* ADD A, @Ri */ |
case 0x27: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
res = cpu_update_flags(cpu, cpu->a, res, add); |
cpu_set_a(cpu, res); |
break; |
case 0x36: /* ADDC A, @Ri */ |
case 0x37: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
res = cpu_update_flags(cpu, cpu->a, res, addc); |
cpu_set_a(cpu, res); |
break; |
case 0x46: /* ORL A, @Ri */ |
case 0x47: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
res = res | cpu->a; |
cpu_set_a(cpu, res); |
break; |
case 0x56: /* ANL A, @Ri */ |
case 0x57: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
res = res & cpu->a; |
cpu_set_a(cpu, res); |
break; |
case 0x66: /* XRL A, @Ri */ |
case 0x67: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
res = res ^ cpu->a; |
cpu_set_a(cpu, res); |
break; |
case 0x76: /* MOV @Ri, imm */ |
case 0x77: |
imm = cpu_fetch(cpu); |
dir = cpu_get_rn(cpu, opcode & 0x01); |
cpu_set_idata(cpu, dir, imm); |
break; |
case 0x86: /* MOV dir, @Ri */ |
case 0x87: |
dir = cpu_fetch(cpu); |
imm = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, imm); |
cpu_set_dir(cpu, dir, res); |
break; |
case 0x96: /* SUBB A, @Ri */ |
case 0x97: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
res = cpu_update_flags(cpu, cpu->a, res, subb); |
cpu_set_a(cpu, res); |
break; |
case 0xa6: /* MOV @Ri, dir */ |
case 0xa7: |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
dir = cpu_get_rn(cpu, opcode & 0x01); |
cpu_set_idata(cpu, dir, res); |
break; |
case 0xb6: /* CJNE @Ri, #imm, rel */ |
case 0xb7: |
imm = cpu_fetch(cpu); |
rel = cpu_fetch(cpu); |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
cpu_update_flags(cpu, res, imm, cjne); |
if(imm != res){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0xc6: /* XCH A,@Ri */ |
case 0xc7: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
cpu_set_idata(cpu, dir, cpu->a); |
cpu_set_a(cpu, res); |
break; |
case 0xd6: /* XCHD A,@Ri */ |
case 0xd7: |
if(cpu->options.bcd){ |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
imm = (res & 0x0f0) | (cpu->a & 0x00f); |
cpu_set_a(cpu, ((cpu->a & 0x0f0) | (res & 0x00f))); |
cpu_set_idata(cpu, dir, imm); |
} |
else{ |
/* Implemented as NOP */ |
cpu->implemented_as_nop = true; |
} |
break; |
case 0xe6: /* MOV A, @Ri */ |
case 0xe7: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
res = cpu_get_idata(cpu, dir); |
cpu_set_a(cpu, res); |
break; |
case 0xf6: /* MOV @Ri, A */ |
case 0xf7: |
dir = cpu_get_rn(cpu, opcode & 0x01); |
cpu_set_idata(cpu, dir, cpu->a); |
break; |
default: /* unimplemented opcode */ |
log_unimplemented(&(cpu->log), opcode); |
ok = false; |
} |
|
if(endless_loop){ |
return false; |
} |
else{ |
return ok; |
} |
} |
|
static bool cpu_exec_rn(cpu51_t *cpu, uint8_t opcode){ |
uint8_t operation, rn, n, res, dir, imm, rel; |
bool ok = true; |
bool endless_loop = false; |
|
operation = (opcode >> 4) & 0x0f; |
n = opcode & 0x07; |
rn = cpu_get_rn(cpu, n); |
|
switch(operation){ |
case 0x00: /* INC Rn */ |
cpu_set_rn(cpu, n, rn+1); |
break; |
case 0x01: /* DEC Rn */ |
cpu_set_rn(cpu, n, rn-1); |
break; |
case 0x02: /* ADD A,Rn */ |
res = cpu_update_flags(cpu, cpu->a, rn, add); |
cpu_set_a(cpu, res); |
break; |
case 0x03: /* ADDC A,Rn */ |
res = cpu_update_flags(cpu, cpu->a, rn, addc); |
cpu_set_a(cpu, res); |
break; |
case 0x04: /* ORL A, Rn */ |
cpu_set_a(cpu, cpu->a | rn); |
break; |
case 0x05: /* ANL A, Rn */ |
cpu_set_a(cpu, cpu->a & rn); |
break; |
case 0x06: /* XRL A, Rn */ |
cpu_set_a(cpu, cpu->a ^ rn); |
break; |
case 0x07: /* MOV Rn, #data */ |
imm = cpu_fetch(cpu); |
cpu_set_rn(cpu, n, imm); |
break; |
case 0x08: /* MOV dir, Rn */ |
dir = cpu_fetch(cpu); |
cpu_set_dir(cpu, dir, rn); |
break; |
case 0x09: /* SUBB A, Rn */ |
res = cpu_update_flags(cpu, cpu->a, rn, subb); |
cpu_set_a(cpu, res); |
break; |
case 0x0a: /* MOV Rn, dir */ |
dir = cpu_fetch(cpu); |
res = cpu_get_dir(cpu, dir); |
cpu_set_rn(cpu, n, res); |
break; |
case 0x0b: /* CJNE Rn, #data, rel */ |
imm = cpu_fetch(cpu); |
rel = cpu_fetch(cpu); |
cpu_update_flags(cpu, rn, imm, cjne); |
if(imm != rn){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0x0c: /* XCH A, Rn */ |
res = cpu->a; |
cpu_set_a(cpu, rn); |
cpu_set_rn(cpu, n, res); |
break; |
case 0x0d: /* DJNZ Rn, rel */ |
rel = cpu_fetch(cpu); |
res = rn - 1; |
cpu_set_rn(cpu, n, res); |
if(res != 0){ |
cpu_rel_jump(cpu, rel); |
cpu->max_cycle_count = true; |
} |
break; |
case 0x0e: /* MOV A, Rn */ |
cpu_set_a(cpu, rn); |
break; |
case 0x0f: /* MOV Rn, A */ |
cpu_set_rn(cpu, n, cpu->a); |
break; |
} |
|
if(endless_loop){ |
return false; |
} |
else{ |
return ok; |
} |
} |
/trunk/tools/b51/src/b51_mcu.h
0,0 → 1,95
/** |
@file b51_mcu.h |
@brief MCU model -- core peripherals. |
*/ |
|
#ifndef S51_PERIPHERALS_H_INCLUDED |
#define S51_PERIPHERALS_H_INCLUDED |
|
#include <stdint.h> |
#include <stdbool.h> |
|
#define MAX_XCODE_SIZE (64 * 1024) |
#define MAX_XDATA_SIZE (64 * 1024) |
|
#define NUM_IRQS (5) |
|
|
/** SFRs for this implementation of the MCU. */ |
/* FIXME remove unused stock SFRs */ |
typedef struct mcu51_sfr_s { |
uint8_t p0; |
uint8_t p1; |
uint8_t p2; |
uint8_t p3; |
uint8_t pcon; |
uint8_t sbuf; |
uint8_t scon; |
uint8_t tcon; |
uint8_t th0; |
uint8_t th1; |
uint8_t tl0; |
uint8_t tl1; |
uint8_t tmod; |
} mcu51_sfr_t; |
|
/** |
MCU model. |
In its present state, this is neither a MCS51 model nor a light52. |
Consider this a dummy. |
*/ |
typedef struct mcu51_s { |
uint8_t xcode[MAX_XCODE_SIZE]; /**< XCODE memory image */ |
uint8_t xdata[MAX_XDATA_SIZE]; /**< XDATA memory image */ |
|
mcu51_sfr_t sfr; /**< MCU (peripheral) SFRs */ |
uint32_t irq_countdown[NUM_IRQS]; /**< Dummy IRQ simulators */ |
} mcu51_t; |
|
/*-- Public functions --------------------------------------------------------*/ |
|
/** |
Initialize MCU model. |
This does NOT perform a reset on the simulated HW. |
Call this once before calling any other function in this API. |
|
@arg mcu MCU model. |
*/ |
extern void mcu_init(mcu51_t *mcu); |
|
/** |
Reset simulated hardware. |
|
@arg mcu MCU model. |
*/ |
extern void mcu_reset(mcu51_t *mcu); |
|
/** |
Write data to SFR and simulate side effects if any. |
|
@arg mcu MCU model. |
@arg dir Address of SFR. |
@arg value Data written to SFR. |
*/ |
extern uint16_t mcu_set_sfr(mcu51_t *mcu, uint8_t dir, uint8_t value); |
|
/** |
Read from SFR. |
|
@arg mcu MCU model. |
@arg dir SFR address. |
@return Value of SFR or undefined value for unimplemented SFRs. |
*/ |
extern uint16_t mcu_get_sfr(mcu51_t *mcu, uint8_t dir); |
|
/** |
Simulates a given number of clock cycles in the peripheral hardware. |
Call this at the end of every simulated instruction to keep the peripheral |
HW state in sync with the CPU state. |
|
@arg mcu MCU model. |
@arg states Number of clock cycles o simulate. |
*/ |
extern void mcu_update(mcu51_t *mcu, uint32_t states); |
|
#endif // S51_PERIPHERALS_H_INCLUDED |
/trunk/tools/b51/src/b51_cpu.h
0,0 → 1,155
/** |
@file b51_cpu.h |
@brief CPU model. |
|
This file includes the CPU simulation model. Excludes the behavior of the |
CPU peripherals, which is done in b51_mcu.c. |
|
When implementing different CPU core models, you should modify this file |
by adding conditional code and new functions. Differences between CPU |
cores are going to be small enough -- cycle counts, implementation of |
certain instructions, etc. |
|
Different cores will have a different set of peripherals, though. That must |
be modelled with a function pointer table against different b51_mcu |
implementations -- meaning one different source file per different core. |
|
TODO CPU & MCU polymorphism to be done. |
*/ |
|
#ifndef S51_H_INCLUDED |
#define S51_H_INCLUDED |
|
#include <stdint.h> |
#include <stdbool.h> |
|
#include "b51_mcu.h" |
#include "b51_log.h" |
|
|
/*-- Configuration macros ----------------------------------------------------*/ |
|
/** Size of IRAM in bytes */ |
#define MAX_IDATA_SIZE (256) |
|
|
/*-- Public data types & macros ----------------------------------------------*/ |
|
|
/** |
MCS51 CPU SFRs. |
FIXME should only include the CPU SFRs and not the peripherals. |
Note that ACC, while accessible as an SFR, is not in this struct and is |
handled separately. |
*/ |
typedef struct cpu51_sfr_s { |
uint8_t b; |
uint8_t dph; |
uint8_t dpl; |
uint8_t ie; |
uint8_t ip; |
uint8_t p0; |
uint8_t p1; |
uint8_t p2; |
uint8_t p3; |
uint8_t pcon; |
uint8_t psw; |
uint8_t sbuf; |
uint8_t scon; |
uint8_t sp; |
uint8_t tcon; |
uint8_t th0; |
uint8_t th1; |
uint8_t tl0; |
uint8_t tl1; |
uint8_t tmod; |
} cpu51_sfr_t; |
|
|
typedef struct cpu51_options_s { |
bool bcd; |
} cpu51_options_t; |
|
|
/** |
CPU object. This is the CPU model, which includes the peripherals block |
and the XDATA and XCODE memory blocks as a member object (struct field). |
*/ |
typedef struct cpu51_s { |
uint8_t idata[MAX_IDATA_SIZE]; /**< IDATA RAM */ |
uint16_t pc; /**< PC -- addr of instruction being run */ |
uint8_t a; /**< ACC */ |
|
cpu51_sfr_t sfr; /**< CPU core (non-peripheral) SFRs */ |
mcu51_t mcu; /**< MCU peripherals model */ |
uint32_t cycles; /**< Clock cycles since last reset */ |
bool max_cycle_count; /**< Last instr. used the max # of cycles */ |
bool implemented_as_nop; /**< Last instr. was decoded as NOP */ |
|
log51_t log; /**< Logger data */ |
|
uint16_t breakpoint; /**< Address of breakpoint */ |
|
cpu51_options_t options; /**< Core implementation options */ |
} cpu51_t; |
|
|
/*-- Public functions --------------------------------------------------------*/ |
|
/** |
Initialize CPU model, including peripheral models. |
This does not reset the CPU or the peripherals. |
Use at least once before calling any other function in this API. |
|
@arg cpu CPU model. |
*/ |
extern void cpu_init(cpu51_t *cpu); |
|
/** |
Simulate a CPU reset, which includes the peripherals too. |
|
@arg cpu CPU model. |
*/ |
extern void cpu_reset(cpu51_t *cpu); |
|
/** |
Run a number of CPU instructions. |
Execution will stop after running num_inst instructions, or if a |
single-instruction infinite loop is detected, or if a breakpoint is hit. |
|
@arg cpu CPU model. |
@arg num_inst Number of instructions to be run. |
@return 0 if execution timed out, |
1 if it was interrupted, |
2 for breakpoints. |
*/ |
extern uint32_t cpu_exec(cpu51_t *cpu, uint32_t num_inst); |
|
/** |
Load object code onto XCODE memory. |
Every object byte that fits the XCODE memory will be loaded onto it. |
Note that bytes out of memory bounds will be dropped silently. |
|
@arg cpu CPU model. |
@arg hex_filename Nam of Intel-HEX file to be loaded. |
@return Number of bytes read from HEX file -- some may have been dropped!. |
*/ |
extern uint16_t cpu_load_code(cpu51_t *cpu, const char *hex_filename); |
|
/** |
Add a new breakpoint at given address. |
The only reasons this function might fail (returning false) are: |
-# Breakpoint address out of XCODE bounds. |
-# Too many breakpoints. |
|
There's no way to delete breakpoints, and the logic is still weak so this |
must be considered a stub. |
|
@arg cpu CPU model. |
@arg address Breakpoint address. |
@return True if the breakpoint could be added. |
*/ |
extern bool cpu_add_breakpoint(cpu51_t *cpu, uint16_t address); |
|
|
#endif // S51_H_INCLUDED |
/trunk/tools/b51/src/main.c
0,0 → 1,158
/** |
@file main.c |
@brief Entry point to b51 simulator. |
|
So farm this program is inly useful for the cosimulation of the light52 test |
bench. It does not simulate any peripheral hardware. Besides, this main |
program is just a stub: no argument parsing, for starters. |
|
*/ |
|
#include <stdint.h> |
#include <stdbool.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
#include "b51_mcu.h" |
#include "b51_cpu.h" |
#include "b51_log.h" |
|
/*-- Local file data ---------------------------------------------------------*/ |
|
/** Value of command line parameters */ |
static struct { |
char *hex_file_name; |
char *trace_logfile_name; |
char *console_logfile_name; |
uint32_t num_instructions; |
bool implement_bcd; |
} args; |
|
|
|
/*-- Local function prototypes -----------------------------------------------*/ |
|
static bool parse_command_line(int argc, char **argv); |
static void usage(void); |
|
|
/*-- Entry point -------------------------------------------------------------*/ |
|
int main(int argc, char **argv){ |
cpu51_t cpu; |
int32_t retval; |
|
cpu_init(&cpu); |
|
/* Parse command line... */ |
if(!parse_command_line(argc, argv)){ |
exit(2); |
} |
/* ...and pass options to CPU model */ |
cpu.options.bcd = args.implement_bcd; |
|
if(!cpu_load_code(&cpu, args.hex_file_name)){ |
exit(1); |
} |
|
log_init(args.trace_logfile_name, args.console_logfile_name); |
printf("\n\n"); |
|
//cpu_add_breakpoint(&cpu, 0x0003); |
cpu_reset(&cpu); |
retval = cpu_exec(&cpu, args.num_instructions); |
|
printf("\n\nExecution finished after %u instructions and %u cycles.\n", |
cpu.log.executed_instructions, cpu.cycles); |
|
switch(retval){ |
case 1 : |
printf("Execution interrupted, cause unknown.\n"); |
break; |
case 2 : |
printf("Execution hit a breakpoint.\n"); |
break; |
default : |
printf("Execution loop returned invalid code %d\n", retval); |
break; |
} |
|
log_close(); |
|
return 0; |
} |
|
/*-- local functions ---------------------------------------------------------*/ |
|
static bool parse_command_line(int argc, char **argv){ |
uint32_t i; |
|
/* Fill command line arguments with default values */ |
args.console_logfile_name = NULL; /* "console_log.txt"; */ |
args.trace_logfile_name = "sw_log.txt"; |
args.hex_file_name = NULL; |
args.num_instructions = 9e8; |
args.implement_bcd = false; |
|
for(i=1;i<argc;i++){ |
if(strcmp(argv[i],"--nologs")==0){ |
/* disable logging */ |
args.console_logfile_name = NULL; |
args.trace_logfile_name = NULL; |
} |
else if(strncmp(argv[i],"--hex=", strlen("--hex="))==0){ |
args.hex_file_name = &(argv[i][strlen("--hex=")]); |
} |
else if(strncmp(argv[i],"--log_con=", strlen("--log_con="))==0){ |
args.console_logfile_name = &(argv[i][strlen("--log_con=")]); |
} |
else if(strncmp(argv[i],"--log=", strlen("--log="))==0){ |
args.trace_logfile_name = &(argv[i][strlen("--log_con=")]); |
} |
else if(strncmp(argv[i],"--ninst=", strlen("--ninst="))==0){ |
/* Number of instructions as decimal integer */ |
if(sscanf(&(argv[i][strlen("--ninst=")]), "%u", |
&(args.num_instructions))==0){ |
printf("Error: expected decimal integer as argument of --ninst\n\n"); |
return false; |
} |
} |
else if(strncmp(argv[i],"--bcd", strlen("--bcd"))==0){ |
printf("Simulating BCD instructions.\n"); |
args.implement_bcd = true; |
} |
else{ |
printf("unknown argument '%s'\n\n",argv[i]); |
usage(); |
return false; |
} |
} |
|
if(args.hex_file_name==NULL){ |
printf("Error: Missing mandatory '--hex=' argument.\n"); |
usage(); |
return false; |
} |
|
return true; |
} |
|
|
static void usage(void){ |
printf("B51: Batch-mode simulator for MCS51 architecture.\n\n"); |
printf("Usage: b51 [options]\n\n"); |
printf("Options:\n\n"); |
printf(" --hex=<filename> -" |
" (mandatory) Name of Intel HEX object code file.\n"); |
printf(" --nint=<dec. number> -" |
" No. of instructions to run. Defaults to a gazillion.\n"); |
printf(" --nologs -" |
" Disable console and execution logging.\n"); |
printf("\n"); |
printf("The program will load the object file, reset the CPU and execute " |
"the specified\nnumber of instructions, then quit.\n"); |
printf("Simulation will only stop after <nint> instructions, when the CPU " |
"enters a\nsingle-instruction endless loop or on an error " |
"condition.\n\n"); |
} |
/trunk/tools/b51/src/b51_log.c
0,0 → 1,120
|
|
#include <stdint.h> |
#include <stdbool.h> |
#include <stdio.h> |
|
#include "b51_cpu.h" |
#include "b51_log.h" |
|
|
static FILE *log_con_fp = NULL; |
static FILE *log_sw_fp = NULL; |
|
extern bool log_init(const char *sw_log_file, const char *con_log_file){ |
if(sw_log_file != NULL){ |
log_sw_fp = fopen(sw_log_file, "w"); |
if(log_sw_fp==NULL){ |
perror("Error opening log file"); |
return false; |
} |
} |
else{ |
/* NULL argument: do not log */ |
log_sw_fp = NULL; /* stdout; */ |
} |
|
if(con_log_file != NULL){ |
log_con_fp = fopen(con_log_file, "w"); |
if(log_con_fp==NULL){ |
perror("Error opening console log file"); |
return false; |
} |
} |
else{ |
/* NULL argument: Redirect to host console */ |
log_con_fp = stdout; |
} |
|
return true; |
} |
|
extern void log_close(void){ |
if(log_sw_fp!=NULL){ |
fclose(log_sw_fp); |
log_sw_fp = NULL; |
} |
if(log_con_fp!=NULL){ |
fclose(log_con_fp); |
log_con_fp = NULL; |
} |
} |
|
|
extern void log_baseline(log51_t *log, uint16_t pc, uint8_t sp, uint8_t a, uint8_t psw){ |
log->pc = pc; |
log->psw = psw; |
log->sp = sp; |
log->a = a; |
} |
|
extern void log_idata(log51_t *log, uint8_t addr, uint8_t value){ |
if(log_sw_fp!=NULL){ |
fprintf(log_sw_fp, "(%04X) [%02X] = %02X\n", log->pc, addr, value); |
} |
} |
|
extern void log_xdata(log51_t *log, uint16_t addr, uint8_t value){ |
if(log_sw_fp!=NULL){ |
fprintf(log_sw_fp, "(%04X) <%04X> = %02X\n", log->pc, addr, value); |
} |
} |
|
extern void log_sfr(log51_t *log, uint8_t addr, uint8_t value){ |
if(log_sw_fp!=NULL){ |
fprintf(log_sw_fp, "(%04X) SFR[%02X] = %02X\n", log->pc, addr, value); |
} |
} |
|
extern bool log_jump(log51_t *log, uint16_t addr){ |
if(log_sw_fp!=NULL){ |
fprintf(log_sw_fp, "(%04X) PC = %04X\n", log->pc, addr); |
} |
return (log->pc == addr); |
} |
|
extern void log_unimplemented(log51_t *log, uint8_t opcode){ |
if(log_sw_fp!=NULL){ |
fprintf(log_sw_fp, "(%04X) UNIMPLEMENTED: %02X\n", log->pc, opcode); |
} |
printf("\n(%04X) UNIMPLEMENTED: %02X\n", log->pc, opcode); |
} |
|
extern void log_reg16(log51_t *log, const char *msg, uint16_t value){ |
if(log_sw_fp!=NULL){ |
fprintf(log_sw_fp, "(%04X) %s = %04X\n", log->pc, msg, value); |
} |
} |
|
extern void log_status(log51_t *log, uint8_t sp, uint8_t a, uint8_t psw){ |
/* Order of checks & log messages matches light52_tb_pkg */ |
if(log_sw_fp!=NULL){ |
if(sp != log->sp){ |
fprintf(log_sw_fp, "(%04X) SP = %02X\n", log->pc, sp); |
} |
if(a != log->a){ |
fprintf(log_sw_fp, "(%04X) A = %02X\n", log->pc, a); |
} |
if((psw) != (log->psw)){ |
fprintf(log_sw_fp, "(%04X) PSW = %02X\n", |
log->pc, psw); |
} |
} |
} |
|
|
extern void log_con_output(char c){ |
if(log_con_fp!=NULL){ |
fprintf(log_con_fp, "%c", c); |
} |
} |
/trunk/tools/b51/src/b51_mcu.c
0,0 → 1,156
|
#include <stdio.h> |
|
#include "b51_mcu.h" |
#include "b51_log.h" |
|
/*-- Private data & data types -----------------------------------------------*/ |
|
|
/*-- Public functions --------------------------------------------------------*/ |
|
extern void mcu_init(mcu51_t *mcu){ |
} |
|
extern void mcu_reset(mcu51_t *mcu){ |
uint32_t i; |
|
for(i=0;i<NUM_IRQS;i++){ |
mcu->irq_countdown[i] = 0; |
} |
} |
|
extern void mcu_update(mcu51_t *mcu, uint32_t states){ |
uint32_t i; |
|
for(i=0;i<NUM_IRQS;i++){ |
if(mcu->irq_countdown[i] > 0){ |
mcu->irq_countdown[i]--; |
|
if(mcu->irq_countdown[i] == 0){ |
switch(i){ |
case 0: /* FIXME external irq 0 unimplemented */ |
break; |
case 1: /* FIXME Timer 0 irq unimplemented */ |
break; |
case 2: /* FIXME external irq 1 unimplemented */ |
break; |
case 3: /* FIXME Timer 1 irq unimplemented */ |
break; |
case 4: /* Serial port irq */ |
mcu->sfr.scon |= 0x030; /* FIXME Tx and Rx interrupts */ |
break; |
default: /* BUG! wrong index */ |
; |
} |
} |
}; |
} |
} |
|
|
extern uint16_t mcu_set_sfr(mcu51_t *mcu, uint8_t dir, uint8_t value){ |
|
if(dir < 0x80) return 0xffff; |
|
switch(dir){ |
case 0x80: /* P0 */ |
mcu->sfr.p0 = value; |
break; |
case 0x90: /* P1 */ |
mcu->sfr.p1 = value; |
break; |
case 0xa0: /* P2 */ |
mcu->sfr.p2 = value; |
break; |
case 0xb0: /* P3 */ |
mcu->sfr.p3 = value; |
break; |
case 0x87: /* PCON */ |
mcu->sfr.pcon = value; |
break; |
case 0x99: /* SBUF */ |
mcu->sfr.sbuf = value; |
log_con_output((char)value); |
/* Simulate a TI interrupt after 4 instruction cycles, arbitrarily */ |
/* FIXME UAR simulation is in bare bones */ |
//mcu->irq_countdown[4] = 4; |
break; |
case 0x98: /* SCON */ |
mcu->sfr.scon = value; |
break; |
case 0x88: /* TCON */ |
mcu->sfr.tcon = value; |
break; |
case 0x89: /* TMOD */ |
mcu->sfr.tmod = value; |
break; |
case 0x8c: /* TH0 */ |
mcu->sfr.th0 = value; |
break; |
case 0x8d: /* TH1 */ |
mcu->sfr.th1 = value; |
break; |
case 0x8a: /* TL0 */ |
mcu->sfr.tl0 = value; |
break; |
case 0x8b: /* TL1 */ |
mcu->sfr.tl1 = value; |
break; |
default: |
/* For undefined SFRs, return 0xffff */ |
return (uint16_t)0xffff; |
} |
|
return 0; |
} |
|
extern uint16_t mcu_get_sfr(mcu51_t *mcu, uint8_t dir){ |
|
if(dir < 0x80) return 0xffff; |
|
switch(dir){ |
case 0x80: /* P0 */ |
return (uint16_t)mcu->sfr.p0; |
break; |
case 0x90: /* P1 */ |
return (uint16_t)mcu->sfr.p1; |
break; |
case 0xa0: /* P2 */ |
return (uint16_t)mcu->sfr.p2; |
break; |
case 0xb0: /* P3 */ |
return (uint16_t)mcu->sfr.p3; |
break; |
case 0x87: /* PCON */ |
return (uint16_t)mcu->sfr.pcon; |
break; |
case 0x99: /* SBUF */ |
return (uint16_t)mcu->sfr.sbuf; |
break; |
case 0x98: /* SCON */ |
return (uint16_t)mcu->sfr.scon | 0x030; |
break; |
case 0x88: /* TCON */ |
return (uint16_t)mcu->sfr.tcon; |
break; |
case 0x89: /* TMOD */ |
return (uint16_t)mcu->sfr.tmod; |
break; |
case 0x8c: /* TH0 */ |
return (uint16_t)mcu->sfr.th0; |
break; |
case 0x8d: /* TH1 */ |
return (uint16_t)mcu->sfr.th1; |
break; |
case 0x8a: /* TL0 */ |
return (uint16_t)mcu->sfr.tl0; |
break; |
case 0x8b: /* TL1 */ |
return (uint16_t)mcu->sfr.tl1; |
break; |
default: |
/* IIF the SFR is undefined we return a 16-bit-wide 0xffff */ |
return (uint16_t)0xffff; |
} |
} |
/trunk/tools/b51/src/util/ihex.h
0,0 → 1,127
#ifndef INTEL_HEX_H |
#define INTEL_HEX_H |
/** |
* \file ihex.h |
* \brief Low-level utility functions to create, read, write, and print Intel HEX8 binary records. |
* \author Vanya A. Sergeev <vsergeev@gmail.com> |
* \date February 2011 |
* \version 1.0.5 |
*/ |
|
#include <stdio.h> |
#include <stdint.h> |
#include <stdlib.h> |
#include <string.h> |
|
/* General definition of the Intel HEX8 specification */ |
enum _IHexDefinitions { |
/* 768 should be plenty of space to read in a Intel HEX8 record */ |
IHEX_RECORD_BUFF_SIZE = 768, |
/* Offsets and lengths of various fields in an Intel HEX8 record */ |
IHEX_COUNT_OFFSET = 1, |
IHEX_COUNT_LEN = 2, |
IHEX_ADDRESS_OFFSET = 3, |
IHEX_ADDRESS_LEN = 4, |
IHEX_TYPE_OFFSET = 7, |
IHEX_TYPE_LEN = 2, |
IHEX_DATA_OFFSET = 9, |
IHEX_CHECKSUM_LEN = 2, |
IHEX_MAX_DATA_LEN = 512, |
/* Ascii hex encoded length of a single byte */ |
IHEX_ASCII_HEX_BYTE_LEN = 2, |
/* Start code offset and value */ |
IHEX_START_CODE_OFFSET = 0, |
IHEX_START_CODE = ':', |
}; |
|
/** |
* All possible error codes the Intel HEX8 record utility functions may return. |
*/ |
enum IHexErrors { |
IHEX_OK = 0, /**< Error code for success or no error. */ |
IHEX_ERROR_FILE = -1, /**< Error code for error while reading from or writing to a file. You may check errno for the exact error if this error code is encountered. */ |
IHEX_ERROR_EOF = -2, /**< Error code for encountering end-of-file when reading from a file. */ |
IHEX_ERROR_INVALID_RECORD = -3, /**< Error code for error if an invalid record was read. */ |
IHEX_ERROR_INVALID_ARGUMENTS = -4, /**< Error code for error from invalid arguments passed to function. */ |
IHEX_ERROR_NEWLINE = -5, /**< Error code for encountering a newline with no record when reading from a file. */ |
}; |
|
/** |
* Intel HEX8 Record Types 00-05 |
*/ |
enum IHexRecordTypes { |
IHEX_TYPE_00 = 0, /**< Data Record */ |
IHEX_TYPE_01, /**< End of File Record */ |
IHEX_TYPE_02, /**< Extended Segment Address Record */ |
IHEX_TYPE_03, /**< Start Segment Address Record */ |
IHEX_TYPE_04, /**< Extended Linear Address Record */ |
IHEX_TYPE_05, /**< Start Linear Address Record */ |
}; |
|
/** |
* Structure to hold the fields of an Intel HEX8 record. |
*/ |
typedef struct { |
uint16_t address; /**< The 16-bit address field. */ |
uint8_t data[IHEX_MAX_DATA_LEN/2]; /**< The 8-bit array data field, which has a maximum size of 256 bytes. */ |
int dataLen; /**< The number of bytes of data stored in this record. */ |
int type; /**< The Intel HEX8 record type of this record. */ |
uint8_t checksum; /**< The checksum of this record. */ |
} IHexRecord; |
|
/** |
* Sets all of the record fields of an Intel HEX8 record structure. |
* \param type The Intel HEX8 record type (integer value of 0 through 5). |
* \param address The 16-bit address of the data. |
* \param data A point to the 8-bit array of data. |
* \param dataLen The size of the 8-bit data array. |
* \param ihexRecord A pointer to the target Intel HEX8 record structure where these fields will be set. |
* \return IHEX_OK on success, otherwise one of the IHEX_ERROR_ error codes. |
* \retval IHEX_OK on success. |
* \retval IHEX_ERROR_INVALID_ARGUMENTS if the record pointer is NULL, or if the length of the 8-bit data array is out of range (less than zero or greater than the maximum data length allowed by record specifications, see IHexRecord.data). |
*/ |
int New_IHexRecord(int type, uint16_t address, const uint8_t *data, int dataLen, IHexRecord *ihexRecord); |
|
/** |
* Reads an Intel HEX8 record from an opened file. |
* \param ihexRecord A pointer to the Intel HEX8 record structure that will store the read record. |
* \param in A file pointer to an opened file that can be read. |
* \return IHEX_OK on success, otherwise one of the IHEX_ERROR_ error codes. |
* \retval IHEX_OK on success. |
* \retval IHEX_ERROR_INVALID_ARGUMENTS if the record pointer or file pointer is NULL. |
* \retval IHEX_ERROR_EOF if end-of-file has been reached. |
* \retval IHEX_ERROR_FILE if a file reading error has occured. |
* \retval IHEX_INVALID_RECORD if the record read is invalid (record did not match specifications or record checksum was invalid). |
*/ |
int Read_IHexRecord(IHexRecord *ihexRecord, FILE *in); |
|
/** |
* Writes an Intel HEX8 record to an opened file. |
* \param ihexRecord A pointer to the Intel HEX8 record structure. |
* \param out A file pointer to an opened file that can be written to. |
* \return IHEX_OK on success, otherwise one of the IHEX_ERROR_ error codes. |
* \retval IHEX_OK on success. |
* \retval IHEX_ERROR_INVALID_ARGUMENTS if the record pointer or file pointer is NULL. |
* \retval IHEX_ERROR_INVALID_RECORD if the record's data length is out of range (greater than the maximum data length allowed by record specifications, see IHexRecord.data). |
* \retval IHEX_ERROR_FILE if a file writing error has occured. |
*/ |
int Write_IHexRecord(const IHexRecord *ihexRecord, FILE *out); |
|
/** |
* Prints the contents of an Intel HEX8 record structure to stdout. |
* The record dump consists of the type, address, entire data array, and checksum fields of the record. |
* \param ihexRecord A pointer to the Intel HEX8 record structure. |
* \return Always returns IHEX_OK (success). |
* \retval IHEX_OK on success. |
*/ |
void Print_IHexRecord(const IHexRecord *ihexRecord); |
|
/** |
* Calculates the checksum of an Intel HEX8 IHexRecord structure. |
* See the Intel HEX8 specifications for more details on the checksum calculation. |
* \param ihexRecord A pointer to the Intel HEX8 record structure. |
* \return The 8-bit checksum. |
*/ |
uint8_t Checksum_IHexRecord(const IHexRecord *ihexRecord); |
|
#endif |
/trunk/tools/b51/src/util/ihex.c
0,0 → 1,170
/* |
* ihex.c |
* Utility functions to create, read, write, and print Intel HEX8 binary records. |
* |
* Written by Vanya A. Sergeev <vsergeev@gmail.com> |
* Version 1.0.5 - February 2011 |
* |
*/ |
|
#include "ihex.h" |
|
/* Initializes a new IHexRecord structure that the paramater ihexRecord points to with the passed |
* record type, 16-bit integer address, 8-bit data array, and size of 8-bit data array. */ |
int New_IHexRecord(int type, uint16_t address, const uint8_t *data, int dataLen, IHexRecord *ihexRecord) { |
/* Data length size check, assertion of ihexRecord pointer */ |
if (dataLen < 0 || dataLen > IHEX_MAX_DATA_LEN/2 || ihexRecord == NULL) |
return IHEX_ERROR_INVALID_ARGUMENTS; |
|
ihexRecord->type = type; |
ihexRecord->address = address; |
memcpy(ihexRecord->data, data, dataLen); |
ihexRecord->dataLen = dataLen; |
ihexRecord->checksum = Checksum_IHexRecord(ihexRecord); |
|
return IHEX_OK; |
} |
|
/* Utility function to read an Intel HEX8 record from a file */ |
int Read_IHexRecord(IHexRecord *ihexRecord, FILE *in) { |
char recordBuff[IHEX_RECORD_BUFF_SIZE]; |
/* A temporary buffer to hold ASCII hex encoded data, set to the maximum length we would ever need */ |
char hexBuff[IHEX_ADDRESS_LEN+1]; |
int dataCount, i; |
|
/* Check our record pointer and file pointer */ |
if (ihexRecord == NULL || in == NULL) |
return IHEX_ERROR_INVALID_ARGUMENTS; |
|
if (fgets(recordBuff, IHEX_RECORD_BUFF_SIZE, in) == NULL) { |
/* In case we hit EOF, don't report a file error */ |
if (feof(in) != 0) |
return IHEX_ERROR_EOF; |
else |
return IHEX_ERROR_FILE; |
} |
/* Null-terminate the string at the first sign of a \r or \n */ |
for (i = 0; i < (int)strlen(recordBuff); i++) { |
if (recordBuff[i] == '\r' || recordBuff[i] == '\n') { |
recordBuff[i] = 0; |
break; |
} |
} |
|
|
/* Check if we hit a newline */ |
if (strlen(recordBuff) == 0) |
return IHEX_ERROR_NEWLINE; |
|
/* Size check for start code, count, addess, and type fields */ |
if (strlen(recordBuff) < (unsigned int)(1+IHEX_COUNT_LEN+IHEX_ADDRESS_LEN+IHEX_TYPE_LEN)) |
return IHEX_ERROR_INVALID_RECORD; |
|
/* Check the for colon start code */ |
if (recordBuff[IHEX_START_CODE_OFFSET] != IHEX_START_CODE) |
return IHEX_ERROR_INVALID_RECORD; |
|
/* Copy the ASCII hex encoding of the count field into hexBuff, convert it to a usable integer */ |
strncpy(hexBuff, recordBuff+IHEX_COUNT_OFFSET, IHEX_COUNT_LEN); |
hexBuff[IHEX_COUNT_LEN] = 0; |
dataCount = strtol(hexBuff, (char **)NULL, 16); |
|
/* Copy the ASCII hex encoding of the address field into hexBuff, convert it to a usable integer */ |
strncpy(hexBuff, recordBuff+IHEX_ADDRESS_OFFSET, IHEX_ADDRESS_LEN); |
hexBuff[IHEX_ADDRESS_LEN] = 0; |
ihexRecord->address = strtol(hexBuff, (char **)NULL, 16); |
|
/* Copy the ASCII hex encoding of the address field into hexBuff, convert it to a usable integer */ |
strncpy(hexBuff, recordBuff+IHEX_TYPE_OFFSET, IHEX_TYPE_LEN); |
hexBuff[IHEX_TYPE_LEN] = 0; |
ihexRecord->type = strtol(hexBuff, (char **)NULL, 16); |
|
/* Size check for start code, count, address, type, data and checksum fields */ |
if (strlen(recordBuff) < (unsigned int)(1+IHEX_COUNT_LEN+IHEX_ADDRESS_LEN+IHEX_TYPE_LEN+dataCount*2+IHEX_CHECKSUM_LEN)) |
return IHEX_ERROR_INVALID_RECORD; |
|
/* Loop through each ASCII hex byte of the data field, pull it out into hexBuff, |
* convert it and store the result in the data buffer of the Intel HEX8 record */ |
for (i = 0; i < dataCount; i++) { |
/* Times two i because every byte is represented by two ASCII hex characters */ |
strncpy(hexBuff, recordBuff+IHEX_DATA_OFFSET+2*i, IHEX_ASCII_HEX_BYTE_LEN); |
hexBuff[IHEX_ASCII_HEX_BYTE_LEN] = 0; |
ihexRecord->data[i] = strtol(hexBuff, (char **)NULL, 16); |
} |
ihexRecord->dataLen = dataCount; |
|
/* Copy the ASCII hex encoding of the checksum field into hexBuff, convert it to a usable integer */ |
strncpy(hexBuff, recordBuff+IHEX_DATA_OFFSET+dataCount*2, IHEX_CHECKSUM_LEN); |
hexBuff[IHEX_CHECKSUM_LEN] = 0; |
ihexRecord->checksum = strtol(hexBuff, (char **)NULL, 16); |
|
if (ihexRecord->checksum != Checksum_IHexRecord(ihexRecord)) |
return IHEX_ERROR_INVALID_RECORD; |
|
return IHEX_OK; |
} |
|
/* Utility function to write an Intel HEX8 record to a file */ |
int Write_IHexRecord(const IHexRecord *ihexRecord, FILE *out) { |
int i; |
|
/* Check our record pointer and file pointer */ |
if (ihexRecord == NULL || out == NULL) |
return IHEX_ERROR_INVALID_ARGUMENTS; |
|
/* Check that the data length is in range */ |
if (ihexRecord->dataLen > IHEX_MAX_DATA_LEN/2) |
return IHEX_ERROR_INVALID_RECORD; |
|
/* Write the start code, data count, address, and type fields */ |
if (fprintf(out, "%c%2.2X%2.4X%2.2X", IHEX_START_CODE, ihexRecord->dataLen, ihexRecord->address, ihexRecord->type) < 0) |
return IHEX_ERROR_FILE; |
|
/* Write the data bytes */ |
for (i = 0; i < ihexRecord->dataLen; i++) { |
if (fprintf(out, "%2.2X", ihexRecord->data[i]) < 0) |
return IHEX_ERROR_FILE; |
} |
|
/* Calculate and write the checksum field */ |
if (fprintf(out, "%2.2X\r\n", Checksum_IHexRecord(ihexRecord)) < 0) |
return IHEX_ERROR_FILE; |
|
return IHEX_OK; |
} |
|
/* Utility function to print the information stored in an Intel HEX8 record */ |
void Print_IHexRecord(const IHexRecord *ihexRecord) { |
int i; |
printf("Intel HEX8 Record Type: \t%d\n", ihexRecord->type); |
printf("Intel HEX8 Record Address: \t0x%2.4X\n", ihexRecord->address); |
printf("Intel HEX8 Record Data: \t{"); |
for (i = 0; i < ihexRecord->dataLen; i++) { |
if (i+1 < ihexRecord->dataLen) |
printf("0x%02X, ", ihexRecord->data[i]); |
else |
printf("0x%02X", ihexRecord->data[i]); |
} |
printf("}\n"); |
printf("Intel HEX8 Record Checksum: \t0x%2.2X\n", ihexRecord->checksum); |
} |
|
/* Utility function to calculate the checksum of an Intel HEX8 record */ |
uint8_t Checksum_IHexRecord(const IHexRecord *ihexRecord) { |
uint8_t checksum; |
int i; |
|
/* Add the data count, type, address, and data bytes together */ |
checksum = ihexRecord->dataLen; |
checksum += ihexRecord->type; |
checksum += (uint8_t)ihexRecord->address; |
checksum += (uint8_t)((ihexRecord->address & 0xFF00)>>8); |
for (i = 0; i < ihexRecord->dataLen; i++) |
checksum += ihexRecord->data[i]; |
|
/* Two's complement on checksum */ |
checksum = ~checksum + 1; |
|
return checksum; |
} |
|
/trunk/tools/b51/src/b51_log.h
0,0 → 1,114
#ifndef LOG_H_INCLUDED |
#define LOG_H_INCLUDED |
|
#include <stdint.h> |
#include <stdbool.h> |
|
|
/** |
Information needed by the MCS51 logger functions. |
Mostly copies of previous values of CPU registers, used to detect and log |
changes to them. |
*/ |
typedef struct log51_s { |
uint16_t pc; |
uint8_t psw; |
uint8_t sp; |
uint8_t a; |
uint32_t executed_instructions; |
} log51_t; |
|
/** |
Open log files for writing (erasing previous contents). |
@return True if both files were open successfully. |
*/ |
extern bool log_init(const char *sw_log_file, const char *con_log_file); |
|
/** Close both log files. */ |
extern void log_close(void); |
|
/** |
Update the logger status: transfer the CPU state to the logger state. |
Do this at the START of every instruction. |
|
@arg log Logger object. |
@arg pc CPU PC value. |
@arg sp CPU SP value. |
@arg a CPU ACC value. |
@arg psw CPU PSW value. |
*/ |
extern void log_baseline(log51_t *log, uint16_t pc, uint8_t sp, uint8_t a, uint8_t psw); |
|
/** |
Log write access to IDATA memory. |
|
@arg log Logger object. |
@arg addr IDATA address written to. |
@arg value Value written to IDATA. |
*/ |
extern void log_idata(log51_t *log, uint8_t addr, uint8_t value); |
|
/** |
Log write access to XDATA. |
|
@arg log Logger object. |
@arg addr XDATA address written to. |
@arg value Value written to XDATA. |
*/ |
extern void log_xdata(log51_t *log, uint16_t addr, uint8_t value); |
|
/** |
Log write access to SFR space. |
|
@arg log Logger object. |
@arg addr Address of SFR written to. |
@arg value Value written to SFR. |
*/ |
extern void log_sfr(log51_t *log, uint8_t addr, uint8_t value); |
|
/** |
Log jump (including calls and returns). |
|
@arg log Logger object. |
@arg addr Jump target address. |
*/ |
extern bool log_jump(log51_t *log, uint16_t addr); |
|
/** |
Log attemp to execute an unimplemented instruction. |
(Unimplemented by the simulator OR by the core). |
|
@arg log Logger object. |
@arg opcode Instruction opcode that triggered the log. |
*/ |
extern void log_unimplemented(log51_t *log, uint8_t opcode); |
|
/** |
Log change to 16-bit register -- DPTR. |
|
@arg log Logger object. |
@arg msg Name of 16-bit register. |
@arg value Value written to register. |
*/ |
extern void log_reg16(log51_t *log, const char *msg, uint16_t value); |
|
/** |
Compare CPU state (as given by register arguments sp, a and psw) with |
logger state and log any changes. |
|
@arg log Logger object. |
@arg sp CPU sp value. |
@arg a CPU ACC value. |
@arg psw CPU psw value. |
*/ |
extern void log_status(log51_t *log, uint8_t sp, uint8_t a, uint8_t psw); |
|
/** |
Log character written to the MCU serial port to serial log file. |
FIXME supports only 1 serial port and 1 serial log file. |
|
@arg c Byte written to the serial port. |
*/ |
extern void log_con_output(char c); |
|
#endif // LOG_H_INCLUDED |
/trunk/tools/b51/bin/b51.exe
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
trunk/tools/b51/bin/b51.exe
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/tools/build_rom/build.bat
===================================================================
--- trunk/tools/build_rom/build.bat (nonexistent)
+++ trunk/tools/build_rom/build.bat (revision 4)
@@ -0,0 +1 @@
+python src/build_rom.py -f ../../test/cpu_test/bin/tb51_cpu.hex -o ../../vhdl/obj_code_pkg.vhdl
\ No newline at end of file
Index: trunk/tools/build_rom/src/build_rom.py
===================================================================
--- trunk/tools/build_rom/src/build_rom.py (nonexistent)
+++ trunk/tools/build_rom/src/build_rom.py (revision 4)
@@ -0,0 +1,272 @@
+#!/usr/bin/env python
+"""
+build_rom.py: Create VHDL package with ROM initialization constant from
+Intel-HEX object code file.
+"""
+__author__ = "Jose A. Ruiz"
+__license__ = "LGPL"
+
+
+"""
+Please see the usage instructions and the comments for function 'main'.
+"""
+
+
+import sys
+import getopt
+
+
+
+def usage():
+ """Print usage instructions"""
+ print ""
+ print "usage:"
+ print "python build_rom.py [arguments]\n"
+ print "Builds VHDL ROM constant from template and Intel HEX object file.\n"
+ print "ALL of the following arguments should be given, in any order:"
+ print "{f|file} Object code file name"
+ print "{c|constant} Name of target VHDL constant"
+ print "{p|package} Name of target VHDL package"
+ print "{n|name} Name of project (used only in comment)"
+ print "{o|output} Target VHDL file name"
+ print ""
+ print "Additionally, any of these arguments can be given:"
+ print "{v|vhdl} VHDL template"
+ print " (defaults to templates/obj_code_kg_template.vhdl)"
+ print "{i|indent} Indentation in VHDL tables (decimal)"
+ print " (defaults to 4)"
+
+
+def help():
+ """Print help message a bit longer than usage message."""
+ print "\nPurpose:\n"
+ print "Reads the code and data binary files and 'slices' them in byte"
+ print "columns."
+ print "The data columns are converted to VHDL strings and then inserted"
+ print "into the vhdl template, in place of tags @code0@ .. @code3@ and "
+ print "@data0@ .. @data3@. Column 0 is LSB and column3 is MSB.\n"
+ print "Tags like @data31@ and @data20@ etc. can be used to initialize"
+ print "memories in 16-bit buses, also split in byte columns.\n"
+ print "Template tags are replaced as follows:"
+ print "@obj_pkg_name@ : Name of package in target vhdl file."
+ print "@const_name@ : Name of constant (VHDL table)."
+ print "@obj_size@ : Total size of code table in bytes."
+ print "@project@ : Project name."
+ print "@xcode_size@ : Size of XCODE memory."
+ print "@xdata_size@ : Size of XDATA memory."
+
+def parse_hex_line(line):
+ """Parse code line in HEX object file."""
+ line = line.strip()
+ slen = int(line[1:3],16)
+ sloc = int(line[3:7],16)
+ stype = line[7:9]
+ sdata = line[9:len(line)-2]
+ schk = int(line[len(line)-2:],16)
+
+ csum = slen + int(sloc / 256) + (sloc % 256) + int(stype,16)
+ bytes = [0, ] * slen
+ for i in range(slen):
+ sbyte = int(sdata[i*2:i*2+2],16)
+ bytes[i] = sbyte;
+ csum = csum + sbyte
+
+ csum = ~csum
+ csum = csum + 1
+ csum = csum % 256
+ if csum != schk:
+ return (None, None)
+
+ return (sloc, bytes)
+
+
+def read_ihex_file(ihex_filename):
+ """
+ Read Intel HEX file into a 64KB array.
+ The file is assumed not to have any object code outside the 64K boundary.
+ Return the 64K array plus the size and bounds of the read data.
+ """
+
+ # CODE array, initialized to 64K of zeros...
+ xcode = [0, ] * 65536
+ # ...and code boundaries, initialized out of range.
+ bottom = 100000
+ top = -1
+ (xcode, top, bottom)
+
+ # Read the whole file to a list of lines...
+ fin = open(ihex_filename, "r")
+ ihex_lines = fin.readlines()
+ fin.close()
+
+ # ...and parse the lines one by one.
+ total_bytes = 0
+ for line in ihex_lines:
+ (address, bytes) = parse_hex_line(line)
+ if address == None:
+ print "Checksum error!"
+ sys.exit(1)
+ total_bytes = total_bytes + len(bytes)
+ for i in range(len(bytes)):
+ xcode[address + i] = bytes[i]
+
+ if address < bottom:
+ bottom = address
+
+ if (address + len(bytes)) > top:
+ top = (address + len(bytes))
+
+ print "Read %d bytes from file '%s'" % (total_bytes, ihex_filename)
+ print "Code range %04xh to %04xh" % (bottom, top)
+ return (xcode, total_bytes, bottom, top)
+
+
+def build_vhdl_code(params, xcode, obj_size):
+ """
+ Read VHDL template file and replace all the tags with the values given in
+ the command line parameters.
+ Return the new file contents as a string.
+ """
+
+ # The resulting VHDL text will be stored here.
+ vhdl_code = ""
+
+
+ # Open file and read it into a list of lines.
+ fin = open(params['template'], "r")
+ lines = fin.readlines()
+ fin.close()
+
+ # Now process the template lines one by one.
+ for line in lines:
+ line = line.strip()
+
+ if line.rfind("@obj_bytes@") >= 0:
+ # insert object code as list of byte literals.
+ obj_str = " "
+ for i in range(obj_size):
+ if i != (obj_size-1):
+ sbyte = "X\"%02x\", " % xcode[i]
+ else:
+ sbyte = "X\"%02x\" " % xcode[i]
+ obj_str = obj_str + sbyte
+ if (i % 8) == 7:
+ obj_str = obj_str + "\n "
+
+ line = line.replace("@obj_bytes@",obj_str)
+
+ elif line.rfind("@obj_size@") >= 0:
+ # Insert object code size (not necessarily equal to xcode_size)
+ line = line.replace("@obj_size@","%d" % (obj_size-1))
+
+ elif line.rfind("@xcode_size@") >= 0:
+ # Insert XCODE memory
+ line = line.replace("@xcode_size@","%d" % (params['xcode_size']))
+
+ elif line.rfind("@xdata_size@") >= 0:
+ # Insert XDATA memory
+ line = line.replace("@xdata_size@","%d" % (params['xdata_size']))
+
+ elif line.rfind("@obj_pkg_name@") >= 0:
+ # Insert package name: hardwired
+ line = line.replace("@obj_pkg_name@",params['package'])
+
+ elif line.rfind("@project_name@") >= 0:
+ # Insert project name
+ line = line.replace("@project_name@",params['project'])
+
+
+ vhdl_code = vhdl_code + line + "\n"
+
+ return vhdl_code
+
+
+def main(argv):
+ """Main body of the program."""
+
+ # Parse command line parameters using GetOpt
+ try:
+ opts, args = getopt.getopt(argv, "hf:n:p:c:o:i:v:",
+ ["help", "file=", "name=", "package=", "constant=",
+ "output=", "indent=", "vhdl=", "xcode=", "xdata=" ])
+ except getopt.GetoptError, err:
+ print ""
+ print err
+ usage()
+ sys.exit(2)
+
+ # Command line parameters, initialized to their default values
+ params = {'project': '',
+ 'package': 'obj_code_pkg',
+ 'indent': 4,
+ 'constant': 'obj_code',
+ 'target': 'obj_code_pkg.vhdl',
+ 'hex': '',
+ 'xcode_size': 2048,
+ 'xdata_size': 0,
+ 'template': "./templates/obj_code_pkg_template.vhdl"
+ }
+
+
+ # Parse coommand line parameters
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ usage()
+ help()
+ exit(1)
+ if opt in ("-v", "--vhdl"):
+ params['template'] = arg
+ elif opt in ("-o", "--output"):
+ params['target'] = arg
+ elif opt in ("-c", "--constant"):
+ params['constant'] = arg
+ elif opt in ("-f", "--file"):
+ params['hex'] = arg
+ elif opt in ("-p", "--package"):
+ params['package'] = arg
+ elif opt in ("-n", "--name"):
+ params['project'] = arg
+ elif opt in ("-i", "--indent"):
+ params['indent'] = int(arg)
+ elif opt in ("--xcode"):
+ params['xcode_size'] = int(arg)
+ elif opt in ("--xdata"):
+ params['xdata_size'] = int(arg)
+
+ # Ok, now
+ if params['hex']:
+ (xcode, total_bytes, bottom, top) = read_ihex_file(params['hex']);
+ else:
+ print "Object HEX file name missing.";
+ usage()
+ return 1
+
+
+ # Make sure the object code fits the implemented XCODE space.
+ # If it doesn't, print a warning and let the user deal with it.
+ # Assuming that XCODE starts at address zero -- that's how the core works.
+ if params['xcode_size'] < top:
+ print "\nWARNING: Object code does not fit XCODE space!\n"
+
+
+ # Build the package source...
+ vhdl_code = build_vhdl_code(params, xcode, top);
+
+ # ...and write it to the target file.
+ fout = None
+ try:
+ fout = open(params['target'], "w")
+ fout.write(vhdl_code)
+ fout.close()
+ print "VHDL code table written to %s" % params['target']
+ except:
+ print "Trouble opening %s for output" % params['target']
+ finally:
+ if fout: fout.close()
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
+ sys.exit(0)
+
+
\ No newline at end of file
Index: trunk/tools/build_rom/templates/obj_code_pkg_template.vhdl
===================================================================
--- trunk/tools/build_rom/templates/obj_code_pkg_template.vhdl (nonexistent)
+++ trunk/tools/build_rom/templates/obj_code_pkg_template.vhdl (revision 4)
@@ -0,0 +1,48 @@
+--------------------------------------------------------------------------------
+-- obj_code_pkg.vhdl -- Application object code in vhdl constant string format.
+--------------------------------------------------------------------------------
+-- Written by build_rom.py for project '@project_name@'.
+--------------------------------------------------------------------------------
+-- Copyright (C) 2012 Jose A. Ruiz
+--
+-- 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
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use work.light52_pkg.all;
+
+package @obj_pkg_name@ is
+
+-- Size of XCODE memory in bytes.
+constant XCODE_SIZE : natural := @xcode_size@;
+-- Size of XDATA memory in bytes.
+constant XDATA_SIZE : natural := @xdata_size@;
+
+-- Object code initialization constant.
+constant object_code : t_obj_code(0 to @obj_size@) := (
+ @obj_bytes@
+ );
+
+
+end package @obj_pkg_name@;