OpenCores
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@;

powered by: WebSVN 2.1.0

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